LumenAlbum
LumenAlbum

Reputation: 165

Updating a dialog from another form

I know there are a lot of similar questions out there and I have read through a lot of them. Unfortunately, I still couldn't solve my problem after reading through them - however I am relatively new to C#. According to docs the problem of not being thread safe results in an InvalidOperationException when using the debugger. This is not the case in my problem.

I've recreated the problem with a simple raw test class to concentrate on my problem.

The main form is supposed to show a kind of a progress dialog.

public partial class ImportStatusDialog : Form
{
    public ImportStatusDialog()
    {
        InitializeComponent();
    }

    public void updateFileStatus(string path)
    {
        t_filename.Text = path;         
    }

    public void updatePrintStatus()
    {      
        t_printed.Text = "sent to printer";
    }

    public void updateImportStatus(string clientName)
    {
        t_client.Text = clientName;
    }

    public void updateArchiveStatus()
    {
        t_archived.Text = "archived";
    }
}

When that code is called without any Invoke() from the main form:

private void button1_Click(object sender, EventArgs e)
    {
        ImportStatusDialog nDialog = new ImportStatusDialog();

        nDialog.Show();

        nDialog.updateFileStatus("test");
        Thread.Sleep(1000);
        nDialog.updateImportStatus("TestClient");
        Thread.Sleep(1000);
        nDialog.updatePrintStatus();
        Thread.Sleep(1000);
        nDialog.updateArchiveStatus();
        Thread.Sleep(1000);

        nDialog.Close();
    }

And even when I call it like this:

private void button3_Click(object sender, EventArgs e)
    {
        ImportStatusDialog nDialog = new ImportStatusDialog();

        nDialog.Show();

        if (this.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate
            {
                nDialog.updateFileStatus("Test");
            });
        }
        else
        {
            nDialog.updateFileStatus("Test");
        }

        Thread.Sleep(1000);

        if (this.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate
            {
                nDialog.updatePrintStatus();
            });
        }
        else
        {
            nDialog.updatePrintStatus();
        }

        Thread.Sleep(1000);

        if (this.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate
            {
                nDialog.updateImportStatus("cName");
            });
        }
        else
        {
            nDialog.updateImportStatus("cName");
        }

        Thread.Sleep(1000);

        if (this.InvokeRequired)
        {
            this.Invoke((MethodInvoker)delegate
            {
                nDialog.updateArchiveStatus();
            });
        }
        else
        {
            nDialog.updateArchiveStatus();
        }

        Thread.Sleep(1000);

        nDialog.Close();
    }

the dialog which looks like this in the designer (in my example)

designer view

will be displayed like that:

dialog at runtime

When I use ShowDialog() instead of Show() the dialog displays correnctly, but as the API Doc points out

You can use this method to display a modal dialog box in your application. When this method is called, the code following it is not executed until after the dialog box is closed

which is not what I want, especially as it would mean that the dialog updating would only happen after it has been closed again.

What am I doing wrong here? This seems to be a trivial problem and yet the solution evades me. Please keep in mind that I am new to C# GUI programming.

Also, I would like to ask what would be the right place for using the Invoke()? Do Would you use it in the main form when calling the dialog methods or rather in the dialog update methods itself?

Upvotes: 2

Views: 1498

Answers (1)

Blorgbeard
Blorgbeard

Reputation: 103447

It doesn't look like you're using multiple threads here, so the invoke stuff is not required. Invoke is only needed for cross-thread calls - you are creating multiple forms, but all your code is running in the same thread.

If you're doing your work in the main UI thread (as implied by the code being in a button click event), then just call Application.DoEvents() periodically to allow the progress form to refresh.

A better solution would be to use a BackgroundWorker for your work, and have it report its progress periodically.

Then you can update the progress form in the BackgroundWorker's ProgressChanged event (which will be executed in the main thread, so you still don't have to invoke anything).

Upvotes: 2

Related Questions