C#跳过DispatcherOperation

时间:2019-02-20 02:26:01

标签: c# asynchronous

我有一个很耗时的工作,我尝试实现异步方法以防止应用程序阻塞。我的代码如下:

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异常的情况下运行程序?

1 个答案:

答案 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;
}