在演示者(MVP)中声明时,如何执行负责更新UI的事件处理程序

时间:2012-08-21 12:58:09

标签: winforms multithreading c#-4.0 mvp

我试图实现MVP模式,并且我遇到了一些与事件处理程序有关的问题。最初我在部分类中声明了这一点。因为它包含逻辑im假设它应该被移动到演示者?

当我将它移动到Presenter时,InvokeRequired / invoke显然会产生错误。因此,除了将整个方法留在视图中之外,我提出的唯一其他选项是将事件处理程序保留在View中,因此InvokeRequired等没有任何问题,但是移动了EventHandler的主体,即行动代表,进入演示者。我不知道这样的方法调用如何工作,因为我使用DI atm在视图之间进行通信 - >演示者,但不知道如何获得演示者 - >图。

    public void CompletionReportNotifier(object sender, VerificationStatusEventArgs e)
    {
        Action action = () =>
        {
            //Display messages depending on whether it was canceled or not.
            if (e.CarriedOutToCompletion == true)
            {
                string logMessage = string.Format("The data verification operation has been completed and {0} errors were found. Please view the error log for additional information.", inputs.NumberOfErrorsFound.ToString());
                _view.UpdateLog(logMessage);
            }
            else
            {
                _view.UpdateLog("The data verification has failed. Please view the error log for additional information.");
            }

            //...
        };

        if (InvokeRequired)
            Invoke(action);
        else
            action();
    }

根据ItsMatt的回复编辑

演示者代码:

    public void CompletionReportNotifier(object sender, VerificationStatusEventArgs e)
    {
        _view.PermanentCsvFileVerificationCancellation = null;

        string logMessage;
        bool inputsVisible = false;

        //Display messages depending on whether it was canceled or not.
        if (e.CarriedOutToCompletion == true)
        {
            logMessage = string.Format("The data verification operation has been completed and {0} errors were found. Please view the error log for additional information.", inputs.NumberOfErrorsFound.ToString());
        }
        else
        {
            logMessage = "The data verification has failed. Please view the error log for additional information.";
        }

        //Assign values to parameters depending on if it failed or errors were encountered.
        if (e.CarriedOutToCompletion != true || inputs.NumberOfErrorsFound > 0)
        {
            inputsVisible = true;
            _view.VerificationCompleted = false;
        }
        else
        {
            _view.VerificationCompleted = true;
        }

        _view.UIUpdate(logMessage, inputsVisible);
    }

查看代码:

    public void UIUpdate(string logMessage, bool inputsVisible)
    {
        Action action = () =>
        {
            UpdateLog(logMessage);
            AccessToCsvFileVerificationInputs(inputsVisible);
            btnDataVerification.Text = "Verify Data";
            DisplayBusyMouseCursor(false);
            VerifyingData = false;
        };
        if (InvokeRequired)
            Invoke(action);
        else
            action();
    }

1 个答案:

答案 0 :(得分:2)

在您的具体情况下,您基本上 - 至少从我在代码片段中看到的内容 - 确定最终显示给用户的日志消息字符串,对吧?

那么使用Func而不是Action呢?这样你就可以在演示者一侧用你在那里获得的任何逻辑创建你的Func委托,让它创建logMessage并在视图执行时返回它。

这样可以保持您在演示者方面的逻辑以及UI端UI的详细信息。是否需要调用Invoke实际上是一个UI问题,而不是主持人的关注,对吧?我想你只是在UI中坚持使用Invoke代码并让它执行传递给它的Func。

我在想这样的事情:

public void CompletionReportNotifier(object sender, VerificationStatusEventArgs e)
{
    Func<string> func = () =>
    {
        string logMessage = string.empty;

        //Display messages depending on whether it was canceled or not.
        if (e.CarriedOutToCompletion == true)
        {
            logMessage = 
                    string.Format("The data verification operation has been completed and {0} errors were found. Please view the error log for additional information.",
                    inputs.NumberOfErrorsFound.ToString());
       }
        else
        {
            logMessage ="The data verification has failed. Please view the error log for additional information.";
        }

        return logMessage;
    };
    _view.UpdateLog(func);
}

在视图中类似

public void UpdateLog(Func func)
{
   if (InvokeRequired) 
   {
      someControl.Invoke((MethodInvoker)(() =>
      {
         Invoke(whateverUi.Text = func());
      }));  
   }
   else
      whateverUi.Text = func();
}

因此,只要Presenter知道,它有一些IView(或者你做的事情 - 我假设Presenter有一个IView但无论如何)有一个UpdateLog方法,可以通过传递一个Func参数来调用它

就View而言,它的UpdateLog方法被某人调用,无论Func输出被使用,UI都会使用它。在我的例子中,我只是将一些控件的文本设置为结果。如果需要调用Invoke,那就是。