1

我想使用 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();
}

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

4

2 回答 2

1

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

更好的解决方法是让它自动安装。然后确保您创建的任何表单都将仅在之前未完成时安装它。把它放在表单创建代码的前面:

        WindowsFormsSynchronizationContext.AutoInstall = true;

最大的优势是,如果代码被重复,您将不会创建它的另一个实例,并且可能会搞砸线程的 ExecutionContext。

请考虑 ShowDialog() 作为另一个修复。如果我没记错的话,那么您现在也遇到了制表符和快捷键的问题。

于 2012-04-20T00:49:39.737 回答
0

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

在 VSTO 应用程序中,它不会。它可能只是默认的,它只是执行方法。Hans Passant 的链接包含您需要的代码,以使其按预期工作。IE:

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

...create and start your background worker here...
于 2012-04-20T00:06:13.350 回答