BackgroundWorker.ProgressChanged和RunWorkerCompletedhandler还想要调用吗?

时间:2012-04-19 17:43:14

标签: c# winforms multithreading vsto backgroundworker

我想使用BackgroundWorker进行后台操作,因为我认为在更新WinForm-Controls时不需要处理“BeginInvoke”等。是对的吗?据我所知,您可以使用ProgressChanged和RunWorkerCompleted事件处理程序直接更新WinForms控件。

但我不能,我虽然得到以下例外:

  

上创建的线程以外的线程访问的控件名称

一些代码:

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!";
        }
    }
}

我不得不说,这不是WinForms应用程序,而是VSTO PowerPoint加载项。当用户单击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();
}

你能告诉我这里有什么问题吗?

2 个答案:

答案 0 :(得分:1)

我发布了链接,但实际上并不认为这是最好的解决方案。很明显,失败的原因是您从未调用Application.Run()或使用Form.ShowDialog()。您可以如图所示明确分配上下文,但如果您不正确,则可能会遇到一些非常棘手的问题。就像分配不止一次一样。

更好的解决方法是让它自动安装。然后确保您创建的任何表单只有在以前没有完成时才会安装它。把它放在表单创建代码的前面:

        WindowsFormsSynchronizationContext.AutoInstall = true;

如果代码重复出现,那么你将不会创建另一个实例,并可能搞砸了线程的ExecutionContext。

请将ShowDialog()视为另一个修复程序。如果我没有弄错的话,你现在也会遇到标签和快捷键击的问题。

答案 1 :(得分:0)

您对Windows窗体的假设是正确的。它的工作方式是BackgroundWorkers使用当前线程的SynchronizationContext。在Windows应用程序中,这将是WindowsFormsSynchronizationContext,它会为您进行编组。

在VSTO应用中,它不会。它可能只是默认的,它只是执行方法。 Hans Passant的链接提供了使其按预期工作所需的代码。即:

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

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