2

我正在使用 WinForms 中的任务从我的 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());
        }
}
4

2 回答 2

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());
        }
    }
于 2012-06-21T08:36:03.870 回答
1

我会为此使用基于事件的异步类型模式。下面是我用来使用 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);
    }
}

我希望这有帮助。

编辑。注意,上面uiSchedulerTaskScheduler针对 UI Thread 的。那是

TaskSheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
于 2012-06-21T08:29:11.280 回答