C# BackgroundWorker.ProgressChanged和RunWorkerCompletedhandler是否仍要调用?
我想使用BackgroundWorker进行后台操作,因为我认为在更新WinForm控件时不需要考虑“BeginInvoke”等问题。是这样吗?据我所知,您可以使用ProgressChanged和RunWorkerCompleted事件处理程序直接更新WinForms控件 但我不能,尽管我有以下例外: 从创建控件的线程以外的线程访问的控件名称 一些代码: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
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击中了靶心。在这种情况下,您需要调用。