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

これには、Event Based Asynchronous- TYPEパターンを使用します。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);
    }
}

これが役立つことを願っています。

編集。上記uiSchedulerTaskSchedulerUI スレッドの であることに注意してください。あれは

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