2016-10-27 4 views
0

Я пишу программное обеспечение, использующее MVP (Model, View, Presenter) для Winform с использованием .net C#. У меня возникла проблема с проектированием класса Presenter, который обрабатывает задачи с большим тиражом (требуется время для расчета и ответа). Я исследовал в Интернете и знаю, как использовать TPL Task или async/await on .net 4.5. Но при этом мне нужно применить его для каждого действия из представления.MVP с задачей длительной работы с ручкой

Теперь я хочу создать класс Presenter, который принимает действия из представления, автоматически выполняет их в других потоках (например, использовать Task, ThreadPool, ...) и обновлять результат обратно в графический интерфейс без каких-либо перекрестных потоков.

Пример: Я хочу управлять роботом, у меня есть RobotView, RobotPresenter и RobotController, которые обрабатывают все действия для отправки в Rotbot devive В классе RobotView я обрабатываю действие HomeRobot, call presenter.

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 

В Presenter: я называю RobotController (Model) для выполнения домашнего действия, которые принимают длительное время (отправить команду на устройство, ждать возвращения ответа)

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 

Так, он работал, но мне нужно примените Task.Run/GetAwaiter ... для всех действий (ArmUp, ArmDown, Extend, Retract, ...). Я также делаю то же самое для других докладчиков (других устройств). Это очень непростое время.

Я хочу создать способ, чтобы каждая функция из вызова вида Presenter.DoSomeThing автоматически запускалась в другом потоке, потому что это задача с большим сроком выполнения.

Надежда кто-то может помочь

С уважением,

+0

Почему бы вам не показать нам какой-то код того, что вы пробовали до сих пор? Было бы намного легче помочь вам. – SharpShade

+1

Какова ваша конкретная проблема? То, что вы говорите, правильно, но что не работает? До сих пор мое предположение: вы действительно не получили, как использовать TPL и async/await. Подсказка: методы презентатора должны быть объявлены как '... async Task DoActionX()', методы модели должны быть объявлены как * async * 'Task' или' Task '. Возможно, вам придется использовать 'await Model.DoActionX(). ConfigureAwait (...)' зависит от вашей ситуации (см. Эту статью [https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) Чтобы получить больше информации). – SharpShade

+0

Я обновил код для четкого значения. – user2927954

ответ

0

Есть два возможных подхода к этому вопросу. Самая изящная и, вероятно, «лучшая практика» (пожалуйста, не стесняйтесь исправить меня, если я ошибаюсь) заключается в том, чтобы сам метод обработчика async void. Здесь будет сказано: Это только случай, где вы должны использовать async void. Всегда используйте async Task!

Если вы не хотите делать асинхронный обработчик, вы также можете использовать Task.Factory.StartNew(PresenterActionMethod).ContinueWith(AnotherHandler);, но это относительно плохой подход. Вам понадобится другой метод обработчика, который будет вызываться из другого потока и, следовательно, должен был вызывать в потоке пользовательского интерфейса, если вы измените какие-либо элементы управления пользовательского интерфейса. Использование 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); 
}