wpf 停止运行 backgroundworker 并开始新的。
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19949718/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stop running backgroundworker and start new one.
提问by Robby Smet
I have a window with a calendar and datagrid.
When the user selects a new date in the calendar I want to query the database for calls made on that date.
我有一个带有日历和数据网格的窗口。
当用户在日历中选择一个新日期时,我想查询数据库以查找在该日期进行的调用。
public HistoryDialog()
{
InitializeComponent();
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
HistoryGrid.SelectionChanged += new SelectionChangedEventHandler(HistoryGrid_SelectionChanged);
}
void calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
startDate = calendar.SelectedDates.OrderBy(x => x.Date).FirstOrDefault();
endDate = calendar.SelectedDates.OrderByDescending(x => x.Date).FirstOrDefault();
if (endDate != startDate)
SelectedDateTextBlock.Text = String.Format("{0:d MMMM}", startDate) + " - " + String.Format("{0:d MMMM}", endDate);
else
SelectedDateTextBlock.Text = String.Format("{0:d MMMM}", startDate);
SearchInDatabase();
}
private void SearchInDatabase()
{
if (worker.IsBusy)
worker.CancelAsync();
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
return;
}
var CallLog = ct.GetCalllogs(startDate, endDate, userID); // Database query
e.Result = CallLog;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
IList CallLog = e.Result as IList;
foreach (CalllogInfo callInfo in CallLog)
{
chvm.CallHistoryList.Add(callInfo);
}
}
But when the user selects a new date while the backgroundworker is still running my program crashes.
但是当用户在后台工作人员仍在运行时选择新日期时,我的程序崩溃了。
How can I stop a running background worker and start a new one ?
如何停止正在运行的后台工作人员并开始一个新的工作人员?
回答by Nico
Now I see you have set the WorkerSupportsCancellationproperty to true.
现在我看到您已将该WorkerSupportsCancellation属性设置为 true。
Now this doesnt actually cancel your BackgroundWorker it simply allows you to call the CancelAsync()method.
现在这实际上并没有取消您的 BackgroundWorker 它只是允许您调用该CancelAsync()方法。
What you need to do is in your method processing periodically check to ensure the working is not pending cancellation from the CancellationPendingproperty. As you check this property when you find it true you can set the Cancel property of the event arguments to true. This will then be available in your RunWorkerCompletedevent. At this point (in your RunWorkerCompletedevent handler) you can then restart the BackgroundWorker.
您需要做的是在您的方法处理中定期检查以确保工作不会等待从CancellationPending属性中取消。当您检查此属性时发现它为 true,您可以将事件参数的 Cancel 属性设置为 true。这将在您的RunWorkerCompleted活动中可用。此时(在您的RunWorkerCompleted事件处理程序中)您可以重新启动BackgroundWorker.
Here is an example using very basic background worker that supports cancellation and responds to the cancel request.
这是一个使用非常基本的后台工作程序的示例,它支持取消并响应取消请求。
public MainWindow()
{
InitializeComponent();
this.DataContext = dataModel;
worker = new BackgroundWorker();
worker.WorkerSupportsCancellation = true;
worker.DoWork += (o, e) =>
{
//do a long running task
for (int i = 0; i < 10; i++)
{
System.Threading.Thread.Sleep(500);
if (worker.CancellationPending)
{
e.Cancel = true;
return;
}
}
};
worker.RunWorkerCompleted += (o, e) =>
{
if (e != null && e.Cancelled)
{
startTheWorker();
return;
}
//TODO: I AM DONE!
};
}
BackgroundWorker worker;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (worker != null && worker.IsBusy)
worker.CancelAsync();
else if(worker != null && !worker.CancellationPending)
startTheWorker();
}
void startTheWorker()
{
if (worker == null)
throw new Exception("How come this is null?");
worker.RunWorkerAsync();
}
As you can see we are having to do all the work of actually cancelling the worker. Hope this helps.
如您所见,我们必须完成实际取消工人的所有工作。希望这可以帮助。
回答by Markus
In addition to the other answers, I want to add the following. The following block of code is responsible for raising the error:
除了其他答案之外,我还想添加以下内容。以下代码块负责引发错误:
private void SearchInDatabase()
{
if (worker.IsBusy)
worker.CancelAsync();
worker.RunWorkerAsync();
}
As you call CancelAsync, execution of your code is continued immediately without waiting until the BackgroundWorker is really stopped. This is the reason why RunWorkerAsync is called while the BackgroundWorker is still running resulting in the error you describe. You should change your code as follows:
当您调用 CancelAsync 时,您的代码会立即继续执行,而无需等到 BackgroundWorker 真正停止。这就是为什么在 BackgroundWorker 仍在运行时调用 RunWorkerAsync 导致您描述的错误的原因。您应该按如下方式更改代码:
private void SearchInDatabase()
{
if (worker.IsBusy)
worker.CancelAsync();
while(worker.IsBusy)
System.Threading.Thread.Sleep(100);
worker.RunWorkerAsync();
}
This assures that the BackgroundWorker finishes its work before starting a new one. In addition, you need to enhance your DoWork-method to check the CancellationPending property more often in order to really stop the BackgroundWorker soon after a cancellation request.
这可确保 BackgroundWorker 在开始新工作之前完成其工作。此外,您需要增强 DoWork 方法以更频繁地检查 CancellationPending 属性,以便在取消请求后立即真正停止 BackgroundWorker。
回答by Alex
Disallowing selections while the worker is doing work would remove the issue without the need to tackle it:
在工作人员工作时禁止选择将消除问题而无需解决它:
void calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
{
// .. cut ..
// disable the calendar and go on
calendar.IsEnabled = false;
SearchInDatabase();
}
private void SearchInDatabase()
{
// No longer needed: selection processing is now "atomic"
// if (worker.IsBusy) worker.CancelAsync();
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// .. cut ..
calendar.IsEnabled = true;
}
Or you could bind worker.IsBusyto calendar.IsEnabledto have it handled "automagically" (while still not having to worry about concurrent executions of the worker method).
或者您可以绑定worker.IsBusy到calendar.IsEnabled“自动”处理它(同时仍然不必担心工作方法的并发执行)。
回答by iMax
Your problem is coming from the cancellation.
When you are in ct.GetCalllogsyour code is blocked and doesn't support cancellation.
In ct.GetCalllogsyou should verify that the backgroundworker isn't in cancel state and then start again with the new value.
您的问题来自取消。当你在ct.GetCalllogs你的代码被阻止并且不支持取消。在ct.GetCalllogs您应该验证BackgroundWorker的不取消状态,然后用新值重新开始。
Here is an element of response how to stop backgroundworker correctly
这是如何正确停止后台工作人员的响应元素

