我有一个很耗时的工作,我尝试实现异步方法以防止应用程序阻塞。我的代码如下:
CancellationTokenSource _cts;
async void asyncMethod()
{
// ..................
_cts = new CancellationTokenSource();
var progress = new Progress<double>(value => pbCalculationProgress.Value = value);
try
{
_cts.CancelAfter(25000);
int count = await awaitMethod(_cts.Token, progress);
}
catch (OperationCanceledException ex)
{
// .......
}
finally
{
_cts.Dispose();
}
// ..................
}
async Task<int> awaitMethod(CancellationToken ct, IProgress<double> progress)
{
var task = Task.Run(() =>
{
ct.ThrowIfCancellationRequested();
sqlParser();
progress.Report(1);
return 0;
});
return await task;
}
void sqlParser()
{
string info = form1TxtBox.Text;
// ................
}
此外,该程序会引发异常,因为sqlParser()在从表单中检索文本时会更新UI线程。解决方案是引入Dispatcher方法,该方法允许UI更新。我将awaitMethod的主体保持不变,只是将sqlParser()放在Dispatcher中:
DispatcherOperation op = Dispatcher.BeginInvoke((Action)(() =>
{
sqlParser();
}));
这里发生了一些有趣的事情:asyncMethod()甚至不敢调用awaitMethod!但是,如果我在sqlParser()内放置一个断点并运行调试器,那么一切都会非常顺利。
请,有人可以解释我在代码中遗漏的内容吗?我应该使用哪种补丁程序才能使Dispatcher正常工作?或者:如何在没有Dispatcher且不引发UI-update异常的情况下运行程序?
答案 0 :(得分:0)
解决方案是引入Dispatcher方法,该方法允许UI更新。
这永远不是一个好的解决方案。后台线程直接进入您的UI会鼓励使用意大利面条式代码。
如何在没有Dispatcher且不引发UI更新异常的情况下运行程序?
将后台线程代码视为其自己的独立组件,与UI完全独立。如果您的后台代码需要UI中的数据,那么请在启动后台代码之前先让您的UI代码读取它,然后将其传递给后台代码。
async void asyncMethod()
{
...
try
{
var data = myUiComponent.Text;
_cts.CancelAfter(25000);
int count = await awaitMethod(data, _cts.Token, progress);
}
...
}
async Task<int> awaitMethod(string data, CancellationToken ct, IProgress<double> progress)
{
var task = Task.Run(() =>
{
ct.ThrowIfCancellationRequested();
sqlParser(data);
progress.Report(1);
return 0;
});
return await task;
}