简体   繁体   中英

BackgroundWorker.ProgressChanged and RunWorkerCompletedhandler still want invoke?

I'd like to use a BackgroundWorker for background operations because I thought there is no need to take care of "BeginInvoke" etc. when updating WinForm-Controls. Is that right? As far as I know, you can update WinForms controls directly by using the ProgressChanged and RunWorkerCompleted eventhandlers.

But I can't, I although get the following exception:

Control control name accessed from a thread other than the thread it was created on

Some code:

public partial class ConfigurationForm : Form
{

    public ConfigurationForm()
    {
        InitializeComponent();
        backgroundWorker1.WorkerReportsProgress = true;
        backgroundWorker1.WorkerSupportsCancellation = true;
        label1.Text = String.Empty;
        // [...]
    }

    private void StartButton_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.IsBusy != true)
        {
            label1.Text = "Converting...";
            backgroundWorker1.RunWorkerAsync();
        }
    }

    private void CancelButton_Click(object sender, EventArgs e)
    {
        if (backgroundWorker1.WorkerSupportsCancellation == true)
        {
            backgroundWorker1.CancelAsync();
        }
        progressBar1.Dispose();
        this.Close();
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        // EXCEPTION here, why?
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        Converter c = new Converter();
        c.Start(worker, e);
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        // EXCEPTION in all cases, why?
        if (e.Cancelled == true)
        {
            label1.Text = "Canceled";
        }
        else if (e.Error != null)
        {
            label1.Text = "Error: " + e.Error.Message;
        }
        else
        {
            label1.Text = "Done!";
        }
    }
}

I have to say, this is not a WinForms application but an VSTO PowerPoint add-in. The Form above gets created by the add-in like this when the user is clicking an icon in the ribbon bar of PowerPoint:

//Do I need [STAThread] here? but doesn't seem to work anyway
private void button1_Click(object sender, RibbonControlEventArgs e)
{
    ConfigurationForm config = new ConfigurationForm();
    config.Show();
}

Can you tell me what's the problem here?

I posted the link but I don't actually think it is the best solution. Clearly the failure occurs because you never called Application.Run() or used Form.ShowDialog(). You can assign the context explicitly as shown but you can get some very tricky problems if you don't do it right. Like assigning it more than once.

The better fix is to ask it to automatically install itself. Which then ensures that whatever form you create will then install it only when it wasn't done before. Put this in front of the form creation code:

        WindowsFormsSynchronizationContext.AutoInstall = true;

With the big advantage that if the code ever gets repeated, you won't create another instance of it and potentially screw up the thread's ExecutionContext.

Do consider ShowDialog() as another fix. If I'm not mistaken then you now also have a problem with tabbing and shortcut keystrokes.

Your assumption would be correct for Windows Forms. The way it works though is BackgroundWorkers uses the SynchronizationContext of the current thread. In a windows app, that will be a WindowsFormsSynchronizationContext , which does the marshalling for you.

In a VSTO app, it won't be. It will probably just be the default one, which simply executes the methods. The link from Hans Passant has the code you need to get it to work as expected. Ie:

System.Threading.SynchronizationContext.SetSynchronizationContext(new WindowsFormsSynchronizationContext());

...create and start your background worker here...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM