我有一个表单,上面有两个组合框。我想根据combobox1.Text
和combobox2.Text
填充combobox2.DataSource
(我假设用户已经完成了combobox1
中的输入,并且正在combobox2
中输入)。所以我有一个combobox2
的事件处理程序,如下所示:
private void combobox2_TextChanged(object sender, EventArgs e)
{
if (cmbDataSourceExtractor.IsBusy)
cmbDataSourceExtractor.CancelAsync();
var filledComboboxValues = new FilledComboboxValues{ V1 = combobox1.Text,
V2 = combobox2.Text};
cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues );
}
由于构建DataSource是一个耗时的过程(它创建一个对数据库的请求并执行它),我决定最好使用BackgroundWorker在另一个进程中执行它。因此,存在这样一个场景:cmbDataSourceExtractor尚未完成其工作,用户又键入了一个符号。在这种情况下,我在此行中得到了一个异常cmbDataSourceExtractor.RunWorkerAsync(filledComboboxValues );
有关BackgroundWorker正忙碌,无法同时执行多个操作的信息。
如何摆脱这个异常?
8条答案
按热度按时间vsikbqxv1#
CancelAsync
实际上不会中止线程或类似的操作。它会向工作线程发送一条消息,指示应该通过BackgroundWorker.CancellationPending
取消工作。正在后台运行的DoWork委托必须定期检查此属性,并自行处理取消操作。棘手的部分是DoWork委托可能阻塞,这意味着必须先完成对DataSource所做的工作,然后才能执行其他操作(如检查CancellationPending)。您可能需要将实际工作移到另一个异步委托(或者更好的是,将工作提交给
ThreadPool
),并让您的主工作线程进行轮询,直到这个内部工作线程触发等待状态,或者它检测到CancellationPending。http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx
http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx
gtlvzcf82#
如果在CancelAsync()和RunWorkerAsync()之间添加一个循环,就可以解决问题
调用Application.DoEvents()的while循环将暂停新工作线程的执行,直到当前工作线程被正确取消。请记住,您仍然需要处理工作线程的取消。
第一个代码片段中的Application.DoEvents()将继续处理GUI线程消息队列,因此即使取消并更新cmbDataSourceExtractor.IsBusy属性也将继续处理(如果您只是添加了continue而不是Application.DoEvents(),则循环将GUI线程锁定为繁忙状态,并且不会处理更新cmbDataSourceExtractor.IsBusy的事件)
4ktjp1zp3#
您必须使用主线程和BackgroundWorker之间共享的标志,例如
BackgroundWorker.CancellationPending
。当您希望BackgroundWorker退出时,只需使用BackgroundWorker.CancelAsync()设置该标志。MSDN提供了一个示例:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancellationpending.aspx
5lwkijsr4#
我的例子。DoWork如下:
DoLengtyWork内部:
在其他内容()中:
您要做的是修改DoLengtyWork和OtherStuff(),使它们成为:
sshcrbum5#
此问题是由于
cmbDataSourceExtractor.CancelAsync()
是异步方法,cmdDataSourceExtractor.RunWorkerAsync(...)
退出时Cancel
操作尚未完成。您应该等待cmdDataSourceExtractor
完成后再调用RunWorkerAsync
。in this SO question解释了如何执行此操作。cgyqldqp6#
我的答案有点不同,因为我尝试过这些方法,但它们不起作用。我的代码使用了一个额外的类,在读取数据库值时,或者在将对象添加到List对象或类似对象之前,在公共静态类中检查布尔标志。请参见下面代码中的更改。我添加了ThreadWatcher.StopThread属性。对于此解释,我将"我不打算恢复当前线程,因为这不是您的问题,但这很简单,只需在访问下一个线程之前将属性设置为false即可...
都很好
现在添加以下类
在你读数据库的课上
别忘了使用finally块来正确地关闭你的数据库连接等等。希望这能有所帮助!如果你觉得有帮助,请标记我。
dzjeubhm7#
在我的情况下,我必须池数据库支付确认进来,然后更新
WPF
用户界面。加速所有进程的机制:
检查完成情况的机制:
窗口关闭时取消的机制:
wfauudbj8#
我同意男人的看法。但有时候你得多加点东西。
工业工程
1)添加此
worker.WorkerSupportsCancellation = true;
2)在类中添加一些方法来完成以下操作
因此在关闭应用程序之前,您必须调用此方法。
3)也许你可以
Dispose, null
所有的变量和定时器都在BackgroundWorker
里面。