任务继续以维护UI线程响应

时间:2012-06-21 07:46:18

标签: c# task-parallel-library

我正在使用WinForms中的Tasks从我的UI线程中删除昂贵的方法。在我的updateComplete和updateFailed任务中,我必须将_updateMessageTaskInProgress设置为false并启用我的控件。有没有办法我可以在一个单独的任务中执行此操作,一旦完成(因为我目前有重复的代码),updateComplete或updateFailed也会继续执行?另外,有没有更好的方法来实现_updateMessageTaskInProgress - 我不希望同时运行多个任务。

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());
        }
}

2 个答案:

答案 0 :(得分:2)

为什么不提取方法?

    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());
        }
    }

答案 1 :(得分:1)

我会使用Event Based Asynchronous-TYPE Pattern来做这件事。我用于使用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);
    }
}

我希望这会有所帮助。

编辑。注意,上面的uiScheduler是UI线程的TaskScheduler。那是

TaskSheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();