1.数据量导出时界面需实时显示进度,且“取消”操作立即生效
关键点:async/await + CancellationToken
疑惑点:什么时候用Invoke?什么时候不用?
private async void btnExport_Click(object sender, EventArgs e)
{
// 1. 创建取消令牌
var cts = new CancellationTokenSource();
// 2. 绑定取消按钮(假设你界面上有个 btnCancel)
btnCancel.Click += (s, ev) => cts.Cancel();
try
{
// 3. 后台执行耗时操作(传递令牌,便于取消)
var data = await Task.Run(() => GetLargeData(cts.Token), cts.Token);
// 4. 回到 UI 线程,直接操作控件(无需 Invoke)
string currentText = textBox1.Text; // 随便读个值,证明在 UI 线程
dataGridView1.DataSource = data;
progressBar1.Value = 100;
}
catch (OperationCanceledException)
{
MessageBox.Show("已取消");
}
finally
{
// 可选:取消按钮事件解绑,避免重复订阅
btnCancel.Click -= (s, ev) => cts.Cancel();
}
}
上面示例代码可以看到,一般情况下,我们使用async/await异步编程,不需要用到Invoke。await之后的代码在执行完毕后,默认回到UI线程(因为SynchronizationContext被捕获),所有后面我们可以直接操作控件,不需要使用Invoke。
那什么时候需用到Invoke执行,使其回到UI线程呢?(如果不先回到UI线程,直接操作UI控件会报:InvalidOperationException(线程间操作无效))
记住一下情况:
①使用了ConfigureAwait(false),意思是执行完成不会自动回到原来线程,这种情况下需要使用Invoke手动回到原来UI线程(一般执行异步方法不用设置,默认是ConfigureAwait(true)执行完自动回到原来主线程)
②在Task.Run内部或异步方法内使用了控件(一般不建议这样写,极其容易引起线程操作异常)
353



被折叠的 条评论
为什么被折叠?



