我在我的WPF中有一个私有的异步void Button_Click
方法,它运行一个非常复杂的SQL查询,可以运行几分钟。我希望用户可以通过单击另一个按钮来停止此方法。我的代码是这样的:
public partial class MainWindow : Window
{
private async void Button_Click(object sender, RoutedEventArgs e)
{
string SQL_Query= " a very long and complicated SQL query ... "
SqlCommand SQL_Query_cmd = new SqlCommand(SQL_Query, conn);
DataTable dt = new DataTable();
await Task.Run(() => {
using (SqlDataAdapter a = new SqlDataAdapter(SQL_Query_cmd))
{ a.Fill(dt);}
});
}
}
我在这个How to use WPF Background Worker链接中读到了关于BackgroundWorker
的信息。但是不知道如何将它集成到我的代码中。我认为,我的“填充datatable”代码已经是异步的,但我不知道如何停止它。假设要结束此方法的按钮名为stop_btn
,其Click方法名为cancelButton_Click
。
请在帖子中写下你的答案,而不是评论。我会非常感激的。
发布于 2021-03-12 23:40:50
下面是如何使用IDbCommand.Cancel
方法和CancellationTokenSource
在服务器端和客户端执行取消操作。
private IDbCommand _activeSqlCommand;
private CancellationTokenSource _cts;
private async void btnExecute_Click(object sender, RoutedEventArgs e)
{
// The _activeSqlCommand and _cts should be null here.
// Otherwise, you may end up with multiple concurrent executions.
Debug.Assert(_activeSqlCommand == null);
Debug.Assert(_cts == null);
var sqlQuery = "A very long and complicated SQL query...";
var localSqlCommand = new SqlCommand(sqlQuery, _connection);
var localCts = new CancellationTokenSource();
_activeSqlCommand = localSqlCommand;
_cts = localCts;
btnExecute.IsEnabled = false;
btnCancel.IsEnabled = true;
try
{
DataTable dataTable = await AsCancelable(Task.Run(() =>
{
var dt = new DataTable();
using (SqlDataAdapter a = new SqlDataAdapter(localSqlCommand))
a.Fill(dt);
return dt;
}, localCts.Token), localCts.Token);
// Here use the dataTable to update the UI
}
catch (OperationCanceledException) { } // Ignore
catch (SqlException ex) when (ex.ErrorCode == CANCEL_ERROR_CODE) { } // Ignore
finally
{
btnCancel.IsEnabled = false;
btnExecute.IsEnabled = true;
// The _activeSqlCommand and _cts should still have the local values here.
Debug.Assert(_activeSqlCommand == localSqlCommand);
Debug.Assert(_cts == localCts);
_activeSqlCommand = null;
_cts = null;
localCts.Dispose();
}
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
_activeSqlCommand?.Cancel();
_cts?.Cancel();
}
private static Task<T> AsCancelable<T>(Task<T> task,
CancellationToken cancellationToken)
{
var cancelable = new Task<T>(() => default, cancellationToken);
return Task.WhenAny(task, cancelable).Unwrap();
}
您必须找出在取消执行时数据库服务器抛出的异常类型,并根据其ErrorCode
或某些其他属性忽略此异常。
https://stackoverflow.com/questions/66598956
复制相似问题