2016-10-27 11 views
0

MVP(Model、View、Presenter)をWinformで.net C#を使用して適用するソフトウェアを作成しています。私は長期間のタスクを処理するPresenterクラスを設計することに問題があります(計算と応答に時間を要します)。 私はインターネットで調査し、TPL Taskまたはasync/await on .net 4.5の使い方を知っています。しかし、そうすることで、私はそれを各行動に適用する必要があります。MVPでハンドルが長い実行タスク

ビューからアクションを受け取り、他のスレッド(Task、ThreadPoolなど)で自動的に実行し、クロススレッド例外なしでGUIに結果を戻すPresenterクラスを設計したいと思います。

例:私はRobotView、RobotPresenter、RobotControllerを持っています。すべてのアクションをRotbot deviveに送信します。 RobotViewクラスでは、私はHomeRobotというアクションを処理し、プレゼンターに電話します。プレゼンターで

Private Sub btnHome_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHome.Click 
     AVPLib.Log.guiLogger.Info("Enter btnHome_Click") 
     Dim strMessageText As String = String.Empty 
     Try 
      strMessageText = AVPLib.ContainerData.GetMessageText("HomeButtonCenterRobotCassettes") 
      If Utils.ShowAVPMessageBox(strMessageText, HOME_TM, MessageBoxIcon.Question) = DialogResult.OK Then 
       **_presenter.HomeRobot()** 
       AVPLib.ContainerData.LogAlarmEvent(AVPLib.ContainerData.TypeUser, AVPLib.ContainerData.LogSource.AVPMainScreen, 
                  "[Main Screen]" & " Home Click") 
      End If 
     Catch ex As Exception 
      AVPLib.Log.avpLogger.Error(ex.ToString()) 
     End Try 
     AVPLib.Log.guiLogger.Info("Leave btnHome_Click") 
    End Sub 

:私はそう

Public Function HomeRobot() As Boolean 
     Dim result As Boolean = False 
     HEventLoggerWrapper.Debug("Enter HomeRobot.") 

     Try 
      _robotView.EnableDisableAllButton(False) 
      Dim taskResult As Task(Of Boolean) = Task.Run(Function() _robotController.SafetyHomeRobot()) 
      taskResult.GetAwaiter().OnCompleted(Sub() result = taskResult.Result) 

     Catch ex As Exception 
      LogParameterUtility.LogErrorParameter(HEventLoggerWrapper.Logger, 
                [GetType]().Name, 
                "HomeRobot", 
                MethodBase.GetCurrentMethod(), ex) 
     End Try 

     HEventLoggerWrapper.Debug("Leave HomeRobot. Result = " & result) 
     Return result 
    End Function 

(リターン応答を待ち、デバイスにコマンドを送信する)長い時間がかかるホームアクションを実行するためにRobotController(モデル)を呼び出し、それが働いたが、私はする必要がありすべてのアクション(ArmUp、ArmDown、Extend、Retract、...)に対してTask.Run/GetAwaiter ...を適用します。他のプレゼンター(他のデバイス)でも同じことをします。それは非常に無駄な時間です。

私はビュー呼び出しPresenter.DoSomeThingからのすべての関数が、長い実行タスクであるため、別のスレッドで自動的に実行されるように設計したいと思います。

ホープ誰かがこの問題には2つの可能なアプローチがあります

+0

これまでに試したことのあるコードを表示してみませんか?あなたを助けるのがずっと簡単になるでしょう。 – SharpShade

+1

あなたの具体的な問題は何ですか?あなたが言うことは正しいのですが、うまくいかないのですか?これまでの私の仮定:あなたは本当にTPLとasync/awaitの使い方を知りませんでした。ヒント:Presenterメソッドは '... async Task DoActionX()'として宣言されなければなりません。モデルメソッドは* async * 'Task'または' Task 'として宣言されなければなりません。状況に応じて 'await Model.DoActionX()。ConfigureAwait(...)'を使用する必要があるかもしれません(この記事[https://msdn.microsoft.com/en-us/magazine/jj991977.aspx ) 詳細については)。 – SharpShade

+0

明確な意味のコードを更新しました – user2927954

答えて

0

よろしくを、助けることができます。私が間違っていれば私を修正することが最も気に入って、おそらく "ベストプラクティス"はハンドラメソッド自体を作ることです非同期void。ここに言われる:これはの場合のみですasync voidを使用する必要があります。それ以外の場合は常にasync Taskを使用してください。

ハンドラを非同期にしたくない場合は、Task.Factory.StartNew(PresenterActionMethod).ContinueWith(AnotherHandler);も使用できますが、これは比較的悪い方法です。別のスレッドから呼び出される別のハンドラメソッドが必要になるため、UIコントロールを変更した場合はUIスレッドで呼び出す必要があります。 UIスレッドをブロックするので、Task.Wait(...)を使用すると機能しません。

これはちょっとした情報です。しかし、このように使うと完璧に動作します。

///================================================================================================= 
/// <summary> Handler in your View class. </summary> 
/// 
/// <param name="sender"> Source of the event. </param> 
/// <param name="e">  Event information. </param> 
///================================================================================================= 
public async void ViewEventHandler(object sender, EventArgs e) 
{ 
    // Set some UI stuff 
    // Here we need to use ConfigureAwait(true) since we will interact with the UI after this method call 
    await PresenterActionMethod().ConfigureAwait(true); 

    // Set some UI stuff again 
} 

///================================================================================================= 
/// <summary> 
///  This method is inside your Presenter class and is expected to return once the long 
///  running method of your Model is finished. 
/// </summary> 
/// 
/// <returns> A Task. </returns> 
///================================================================================================= 
public async Task PresenterActionMethod() 
{ 
    // Do stuff 
    await ModelLongRunningTaskMethod().ConfigureAwait(false); 
    // Do other stuff 
} 

///================================================================================================= 
/// <summary> 
///  This method is inside your Model class and is expected to be a long-running method. 
/// </summary> 
/// 
/// <returns> A Task. </returns> 
///================================================================================================= 
public async Task ModelLongRunningTaskMethod() 
{ 
    // ... do your stuff here 
    // You should use ConfigureAwait(false) here since you don't need the captured context 
    // this improves performance and reduces the risk of deadlocks 
    await Task.Delay(6000).ConfigureAwait(false); 
} 
関連する問題