C# 任务继续以保持UI线程响应能力

C# 任务继续以保持UI线程响应能力,c#,task-parallel-library,C#,Task Parallel Library,我正在使用WinForms中的任务从UI线程中删除昂贵的方法。在我的updateComplete和updateFailed任务中,我必须将_UpdateMessageAskinProgress设置为false并启用我的控件。有什么方法可以在一个单独的任务中做到这一点,其中updateComplete或updateFailed在完成后继续执行(因为我目前有重复的代码)?另外,有没有更好的方法来实现_updateMessageAskinProgress?我不希望同时运行多个任务 private vo

我正在使用WinForms中的任务从UI线程中删除昂贵的方法。在我的updateComplete和updateFailed任务中,我必须将_UpdateMessageAskinProgress设置为false并启用我的控件。有什么方法可以在一个单独的任务中做到这一点,其中updateComplete或updateFailed在完成后继续执行(因为我目前有重复的代码)?另外,有没有更好的方法来实现_updateMessageAskinProgress?我不希望同时运行多个任务

private void PerformUpdate()
{
    if (!_updateMessageTaskInProgress)
        {
            LoadButton.Enabled = false;
            MonthEndDateEdit.Enabled = false;
            BankIssuerListEdit.Enabled = false;

            Task updateMessages = Task.Factory.StartNew(() =>
            {
                _updateMessageTaskInProgress = true;

                ExpensiveMethod();
            });

            // Task runs when updateMessages completes without exception.  Runs on UI thread.
            Task updateComplete = updateMessages.ContinueWith(update =>
            {
                DoSuccessfulStuff();

                _updateMessageTaskInProgress = false;
                LoadButton.Enabled = true;
                MonthEndDateEdit.Enabled = true;
                BankIssuerListEdit.Enabled = true;
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.NotOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());

            // Task runs when updateMessages completes with exception.  Runs on UI thread.
            Task updateFailed = updateMessages.ContinueWith(task =>
            {
                DoFailureStuff();

                _updateMessageTaskInProgress = false;
                LoadButton.Enabled = true;
                MonthEndDateEdit.Enabled = true;
                BankIssuerListEdit.Enabled = true;
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
        }
}
我会用这个。下面是我使用TPL将方法剥离到后台线程的代码的简化版本

private void TaskSpin(TaskScheduler uiScheduler, 
                      Func<TaskScheduler, object[], bool> asyncMethod, 
                      object[] methodParameters)
{
    try
    {
        Task asyncTask = Task.Factory.StartNew<bool>(() => 
            asyncMethod(uiScheduler, methodParameters));

        // Callback for finish/cancellation.
        asyncTask.ContinueWith(task =>
        {
            // Check task status.
            switch (task.Status)
            {
                // Handle any exceptions to prevent UnobservedTaskException.             
                case TaskStatus.RanToCompletion:
                    if (asyncTask.Result)
                        UpdateUI(uiScheduler, "OK");
                    else
                    {
                        string strErrComplete = "Process failed.";
                        UpdateUI(uiScheduler, strErrComplete);
                    }
                    break;
                case TaskStatus.Faulted:
                    string strFatalErr = String.Empty;
                    UpdateUI(uiScheduler, "Fatal Error);
                    if (task.Exception != null)
                        strFatalErr = task.Exception.InnerException.Message;
                    else
                        strFatalErr = "Operation failed";
                    MessageBox.Show(strFatalErr);
                    break;
            }
            asyncTask.Dispose();
            return;
        }, TaskScheduler.FromCurrentSynchronizationContext());
    }
    catch (Exception eX)
    {
        Utils.ErrMsg(eX.Message);
    }
}

你为什么不提取一个方法呢

    private void SetLock(bool lock)
    {
        LoadButton.Enabled = !lock;
        MonthEndDateEdit.Enabled = !lock;
        BankIssuerListEdit.Enabled = !lock;
        _updateMessageTaskInProgress = lock;
    }

    private void PerformUpdate()
    {
        if (!_updateMessageTaskInProgress)
        {
            SetLock(true);
            Task updateMessages = Task.Factory.StartNew(() =>
            {
                ExpensiveMethod();
            });

            // Task runs when updateMessages completes without exception.  Runs on UI thread.
            Task updateComplete = updateMessages.ContinueWith(update =>
            {
                DoSuccessfulStuff();
                SetLock(false);
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.NotOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());

            // Task runs when updateMessages completes with exception.  Runs on UI thread.
            Task updateFailed = updateMessages.ContinueWith(task =>
            {
                DoFailureStuff();
                SetLock(false);
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
        }
    }

您必须访问任务。失败的处理程序中存在异常,以避免任务终结时出现异常您的
\u updateMessageAskinProgress
具有竞争条件:如果两个任务几乎同时启动,则两个任务可能同时运行。问了这么多问题:这是一个怎样的EAP?(我在代码中没有看到任何事件。)将
asyncTask
作为从未使用过的参数有什么意义?为什么
asynchmethod
TaskScheduler
作为参数?它是EAP-这里是
任务。ContinueWith
是我们的事件。延续执行通常由AsyncCallback委托执行的工作。当antecedent完成并且数据缓冲区已填充时,将调用它<使用code>asyncTask,它被传递到方法中以供我使用(我在问题中声明,这是我所拥有的一些代码的一个修剪版本-也许我应该再修剪一下:)。最后,将
uiScheduler
传递到方法中,以便在该方法中可以更新UI线程。这实际上不是EAP。EAP实际上使用事件,例如
ContinueWith
不是事件,这是一种传递委托的方法。我提供的指向MSDN的链接建议使用相反的方法。。。EAP本质上是为多线程实现提供大量工具的任何东西(不是吗?)。尽管对于第三方物流来说,这可能需要很多伪装,但我认为这是基于文档中所述的伪装之一。你的观点被采纳了……如果你阅读了你链接的文档中的第二个项目符号,它准确地描述了EAP的样子:一个方法和一个
完成的
事件。其他任何东西都不是EAP。
    private void SetLock(bool lock)
    {
        LoadButton.Enabled = !lock;
        MonthEndDateEdit.Enabled = !lock;
        BankIssuerListEdit.Enabled = !lock;
        _updateMessageTaskInProgress = lock;
    }

    private void PerformUpdate()
    {
        if (!_updateMessageTaskInProgress)
        {
            SetLock(true);
            Task updateMessages = Task.Factory.StartNew(() =>
            {
                ExpensiveMethod();
            });

            // Task runs when updateMessages completes without exception.  Runs on UI thread.
            Task updateComplete = updateMessages.ContinueWith(update =>
            {
                DoSuccessfulStuff();
                SetLock(false);
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.NotOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());

            // Task runs when updateMessages completes with exception.  Runs on UI thread.
            Task updateFailed = updateMessages.ContinueWith(task =>
            {
                DoFailureStuff();
                SetLock(false);
            }, System.Threading.CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
        }
    }