C# BackgroundWorker.ProgressChanged和RunWorkerCompletedhandler是否仍要调用?

C# BackgroundWorker.ProgressChanged和RunWorkerCompletedhandler是否仍要调用?,c#,winforms,multithreading,vsto,backgroundworker,C#,Winforms,Multithreading,Vsto,Backgroundworker,我想使用BackgroundWorker进行后台操作,因为我认为在更新WinForm控件时不需要考虑“BeginInvoke”等问题。是这样吗?据我所知,您可以使用ProgressChanged和RunWorkerCompleted事件处理程序直接更新WinForms控件 但我不能,尽管我有以下例外: 从创建控件的线程以外的线程访问的控件名称 一些代码: public partial class ConfigurationForm : Form { public Configurati

我想使用BackgroundWorker进行后台操作,因为我认为在更新WinForm控件时不需要考虑“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();
}

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

您的假设对于Windows窗体是正确的。它的工作方式是使用当前线程的同步上下文。在windows应用程序中,这将是一个
WindowsFormsSynchronizationContext
,它为您进行编组

在VSTO应用程序中,不会出现这种情况。它可能只是默认的一个,它只是执行这些方法。来自Hans Passant的链接包含使其按预期工作所需的代码。即:

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

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

对于Windows窗体,您的假设是正确的。它的工作方式是使用当前线程的同步上下文。在windows应用程序中,这将是一个
WindowsFormsSynchronizationContext
,它为您进行编组

在VSTO应用程序中,不会出现这种情况。它可能只是默认的一个,它只是执行这些方法。来自Hans Passant的链接包含使其按预期工作所需的代码。即:

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

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

我发布了链接,但我并不认为这是最好的解决方案。很明显,失败是因为您从未调用Application.Run()或使用过Form.ShowDialog()。您可以如图所示显式分配上下文,但如果操作不当,可能会遇到一些非常棘手的问题。喜欢多次分配它

更好的解决方法是让它自动安装自己。这样可以确保无论您创建什么表单,都只在以前没有安装过的情况下安装它。将其放在表单创建代码前面:

        WindowsFormsSynchronizationContext.AutoInstall = true;
最大的优点是,如果代码被重复,您将不会创建它的另一个实例,并且可能会破坏线程的ExecutionContext


将SdidiAudio()视为另一个修复。如果我没有弄错的话,那么你现在也遇到了制表符和快捷键的问题。

我发布了链接,但我并不认为这是最好的解决方案。很明显,失败是因为您从未调用Application.Run()或使用过Form.ShowDialog()。您可以如图所示显式分配上下文,但如果操作不当,可能会遇到一些非常棘手的问题。喜欢多次分配它

更好的解决方法是让它自动安装自己。这样可以确保无论您创建什么表单,都只在以前没有安装过的情况下安装它。将其放在表单创建代码前面:

        WindowsFormsSynchronizationContext.AutoInstall = true;
最大的优点是,如果代码被重复,您将不会创建它的另一个实例,并且可能会破坏线程的ExecutionContext


将SdidiAudio()视为另一个修复。如果我没有弄错的话,那么您现在也遇到了制表符和快捷键击的问题。

请检查此项,UI控件只能从主UI线程中触摸。后台工作线程与UI线程不同,因此无法直接访问UI控件。WinForms和WPF都是这种情况,“每个VSTO加载项都放置在其自己的appdomain中,部分是出于隔离原因……”后台工作程序文档声明“BackgroundWorker事件不会跨appdomain边界封送”。您的假设和期望对于普通应用程序是正确的。ProgressChanged处理程序应该在创建辅助线程的线程上运行。但是我想,@Tung击中了靶心。在这种情况下,您需要调用。请检查,UI控件只能从主UI线程进行触摸。后台工作线程与UI线程不同,因此无法直接访问UI控件。WinForms和WPF都是这种情况,“每个VSTO加载项都放置在其自己的appdomain中,部分是出于隔离原因……”后台工作程序文档声明“BackgroundWorker事件不会跨appdomain边界封送”。您的假设和期望对于普通应用程序是正确的。ProgressChanged处理程序应该在创建辅助线程的线程上运行。但是我想,@Tung击中了靶心。在这种情况下,您需要调用。