我有一个调用其中一个方法的线程,现在这个方法执行一个查询,可能需要很长时间才能完成40分钟左右,
我想让用户可以选择取消此操作(意味着停止线程并停止查询以释放数据库)。
我应该提一下,我正在使用.net 4.5,SQL SERVER DB和C#开发WPF应用程序。
答案 0 :(得分:4)
你应该使用backgroundworker,这正是你想要的。
Eather从工具箱中拖放它或在代码后面创建它。它支持取消,报告进度,完成时通知并知道它是否正在运行。
这是一个例子。
void method(){
BackgroundWorker worker = new BackgroundWorker();
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.ProgressChanged += worker_ProgressChanged;
worker.DoWork += worker_DoWork;
worker.WorkerSupportsCancellation = true;
if(!worker.IsBusy)
{
worker.RunWorkerAsync();
}
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do whatever needs to be done on the other thread here.
object argument = e.Argument; //if passed argument in RunWorkerAsync().
object result = new object();
e.Result = result;
//after making worker global, you can report progress like so:
worker.ReportProgress(50); //you can also pass a userState, which can be any object, to show some data already.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//you can update a progress bar in here
int progress = e.ProgressPercentage;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//when done
}
void CancelTheTask()
{
if (worker.IsBusy)
{
//make worker global first, but then
worker.CancelAsync();
}
}
要注意的重要事项:切勿在{{1}}方法中使用未在其中创建的资源。因此,在后台worker中将您需要的东西作为Arguments传递。而且背景工作者创建的东西不应该设置为全局变量ether,传递结果。
取消时,DoWork
也会被解雇。现在,对数据库的查询已经在执行,因此即使您的应用程序丢失了所有资源,它仍然在运行。
要取消它,我们需要知道你如何执行查询,就像提到的@S.Akbari是一种方式。实体框架6还支持取消。
为此:check this when using Queryable
或者没有实体框架的solution。
答案 1 :(得分:2)
使用Task Parallel Library (TPL),您可以使用Task Cancellation模式。
答案 2 :(得分:2)
当您在等待查询时阻止线程时,它对于停止任何操作都没用。
确保可以从UI访问查询的SqlConnection并关闭它。放弃线程,它将终止(有一个错误,你必须压制)。
答案 3 :(得分:1)
如果UI线程正在进行长时间操作,则无法进行处理
UI请求。这也称为无响应。
像这样使用ThreadPool
:
CancellationTokenSource ct;//instantiate it before ThreadPool.QueueUserWorkItem line
private void operation_Click(object sender, RoutedEventArgs e)
{
ct = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(_ =>
{
var result = LongTimeOperation();//set the operation in another thread so that the UI thread is kept responding
//use the Dispatcher to "return" to the UI thread
Dispatcher.BeginInvoke(new Action(() =>
{
//Use result for example : Label1.Text = result.ToString();
}));
});
}
要让用户选择能够取消操作,请使用CancellationTokenSource
,如下所示:
private void cancel_Click(object sender, RoutedEventArgs e)
{
if (ct != null)
{
ct.Cancel();
ct= null;
}
}
注意:在LongTimeOperation
()中,您必须再添加一个类型为CancellationToken
的参数
private float LongTimeOperation(CancellationToken ct)
{
if (ct.IsCancellationRequested)
return -1;
....
....
}
此link对于托管主题中的Cancellation
非常有用。
答案 4 :(得分:-1)
这是一个常见问题。但在WPF
和WinForm
中,我想使用BackGroundWorker
。见Here