繁体   English   中英

事件冒泡和MVP:ASP.NET

[英]Event Bubbling and MVP: ASP.NET

我正在尝试学习MVP

它在ASP.NET中使用Web表单。 我有两个用户控件CurrentTimeView.ascx和MonthViewControl.ascx。 CurrentTimeView显示时间。 有一个文本框可在同一控件中添加日期。 新获得的日期称为“结果日期”。 单击按钮添加天数时,将引发一个事件“ myBtnAddDaysClickedEvent”。

在MonthViewControl上,有一个标签显示“结果日期”的月份。 目前,我正在为变量“ monthValueToPass”设置一个样本值(因为我不知道如何正确执行)。 如何设置monthValueToPass变量的值以使其符合MVP模型?

string monthValueToPass = "TEST";
monthPresenter.SetMonth(monthValueToPass);

期望创建易于执行单元测试并且不违反MVP架构的MVP。

注意:尽管这是一个简单的示例,但我期望使用MVP和验证机制对GridView控件中的数据绑定有答案。

注意:视图可以完全独立于演示者吗?

注意:每个用户控件在这里都是单独的视图

注意:同一演示者是否可以有多个视图(例如,基于其权限的不同用户的不同控件?)

指南

  1. 模型视图演示者-准则

-完整代码-

using System;
public interface ICurrentTimeView
{
    //Property of View
    DateTime CurrentTime 
    {
        set; 
    }
    //Method of View
    void AttachPresenter(CurrentTimePresenter presenter);
}

using System;
public interface IMonthView
{
    //Property of View
    string MonthName 
    {
        set; 
    }

    //Method of View
    //View interface knows the presenter
    void AttachPresenter(MonthPresenter presenter);     
}

using System;
public class CurrentTimePresenter 
{
    private ICurrentTimeView view;

    //Constructor for prsenter
    public CurrentTimePresenter(ICurrentTimeView inputView) 
    {
        if (inputView == null)
        {
            throw new ArgumentNullException("view may not be null");
        }
    }
    this.view = inputView;
}

//Method defined in Presenter
public void SetCurrentTime(bool isPostBack) 
{
    if (!isPostBack) 
    {
        view.CurrentTime = DateTime.Now;
    }
}

//Method defined in Presenter
public void AddDays(string daysUnparsed, bool isPageValid) 
{
    if (isPageValid) 
    {
        view.CurrentTime = DateTime.Now.AddDays(double.Parse(daysUnparsed));           
    }
}

using System;
public class MonthPresenter
{
    private IMonthView monthView;

    //Constructor for prsenter
    public MonthPresenter(IMonthView inputView)
    {
        if (inputView == null)
        {
           throw new ArgumentNullException("view may not be null");
        }
        this.monthView = inputView;
    }


    //Method defined in Presenter
    //How does presenter decides the required value.
    public void SetMonth(string monthValueInput) 
    {
       if (!String.IsNullOrEmpty(monthValueInput))
       {
          monthView.MonthName = monthValueInput;
       }
       else
       {

       }        
    }   
}

用户控制1

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CurrentTimeView.ascx.cs" Inherits="Views_CurrentTimeView" %>

<asp:Label id="lblMessage" runat="server" /><br />
<asp:Label id="lblCurrentTime" runat="server" /><br />
<br />

<asp:TextBox id="txtNumberOfDays" runat="server" />
<asp:Button id="btnAddDays" Text="Add Days" runat="server" OnClick="btnAddDays_OnClick" ValidationGroup="AddDays" />

using System;
using System.Web.UI;
public partial class Views_CurrentTimeView : UserControl, ICurrentTimeView
{
   //1. User control has no method other than view defined method for attaching presenter
   //2. Properties has only set method

   private CurrentTimePresenter presenter;

   // Delegate 
   public delegate void OnAddDaysClickedDelegate(string strValue);

   // Event 
   public event OnAddDaysClickedDelegate myBtnAddDaysClickedEvent;

   //Provision for getting the presenter in User Control from aspx page.
   public void AttachPresenter(CurrentTimePresenter presenter)
   {
       if (presenter == null)
       {
         throw new ArgumentNullException("presenter may not be null");
       }
       this.presenter = presenter;
   }

   //Implement View's Property
   public DateTime CurrentTime
   {
      set
      {
        //During set of the property, set the control's value
        lblCurrentTime.Text = value.ToString();
      }
   }

   //Event Handler in User Control
   protected void btnAddDays_OnClick(object sender, EventArgs e)
   {
      if (presenter == null)
      {
         throw new FieldAccessException("presenter null");
      }

      //Ask presenter to do its functionality
      presenter.AddDays(txtNumberOfDays.Text, Page.IsValid);

      //Raise event
      if (myBtnAddDaysClickedEvent != null)
      {
        myBtnAddDaysClickedEvent(string.Empty);
      }
   }     
}

用户控制2

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MonthViewControl.ascx.cs" Inherits="Views_MonthViewControl" %>

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class Views_MonthViewControl : System.Web.UI.UserControl, IMonthView
{
   //1. User control has no method other than view defined method for attaching presenter
   //2. Properties has only set method

   private MonthPresenter presenter;

   //Provision for gettng the presenter in User Control from aspx page.
   public void AttachPresenter(MonthPresenter presenter)
   {
      if (presenter == null)
      {
         throw new ArgumentNullException("presenter may not be null");
      }
      this.presenter = presenter;
   }

   //Implement View's Property
   public string MonthName
   {
      set
      {
        //During set of the popert, set the control's value
        lblMonth.Text = value.ToString();
      }
   }

   protected void Page_Load(object sender, EventArgs e)
   {

   }    
}

ASPX页面

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ShowMeTheTime.aspx.cs"      Inherits="ShowTime" %>

<%@ Register TagPrefix="mvpProject" TagName="CurrentTimeView" Src="Views/CurrentTimeView.ascx" %>

<%@ Register TagPrefix="month" TagName="MonthView" Src="Views/MonthViewControl.ascx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>PAGE TITLE </title>
</head>
<body>
<form id="form1" runat="server">

    <mvpProject:CurrentTimeView id="ucCtrlcurrentTimeView" runat="server" 
    />
    <br />
    <br />
    <month:MonthView id="ucCtrlMonthView" runat="server" />

</form>
</body>
</html>

using System;
using System.Web.UI;

public partial class ShowTime : Page
{
    CurrentTimePresenter currentTimePresenter;
    MonthPresenter monthPresenter;

    protected void Page_Load(object sender, EventArgs e) 
    {
       HelperInitCurrentTimeView();
       HelperInitMonth();
    }

    private void HelperInitMonth()
    {
       //Create presenter
       monthPresenter = new MonthPresenter(ucCtrlMonthView);

       //Pass the presenter object to user control
       ucCtrlMonthView.AttachPresenter(monthPresenter);
    }

    private void HelperInitCurrentTimeView() 
    { 
       //Cretes presenter by passing view(user control) to presenter.
       //User control has implemented IView
       currentTimePresenter = new CurrentTimePresenter(ucCtrlcurrentTimeView);

        //Pass the presenter object to user control
        ucCtrlcurrentTimeView.AttachPresenter(currentTimePresenter);

        //Call the presenter action to load time in user control.
        currentTimePresenter.SetCurrentTime(Page.IsPostBack);

        //Event described in User Control ???? Subsribe for it.
        ucCtrlcurrentTimeView.myBtnAddDaysClickedEvent += new Views_CurrentTimeView.OnAddDaysClickedDelegate(CurrentTimeViewControl_AddButtonClicked_MainPageHandler);        
    }

    void CurrentTimeViewControl_AddButtonClicked_MainPageHandler(string strValue)
    {
       string monthValue = "l";
       monthPresenter.SetMonth("SAMPLE VALUE");
       //myGridCntrl.CurentCharacter = theLetterCtrl.SelectedLetter;
       //myGridCntrl.LoadGridValues();
    }
}

一些MVP讨论:

模型视图演示者-准则

在MVP中写验证的位置

MVP-视图应该能够直接调用presenter方法还是应该始终引发事件?

MVP事件或财产

MVP中的模型-事件

MVP-主持人应该使用会话吗?

为什么在大多数ASP.NET MVP实现中,Presenter都附加到View事件,而不是View调用Presenter方法?

公开方法或订阅View事件

MVP模式,对演示者有多少视图?

MVP和UserControls以及调用

ASP.NET Web窗体-模型视图演示者和用户控件控件

限制违反体系结构-ASP.NET MVP

表示层中的控件修改

将视图,演示文稿和ASP.NET Web窗体的 Web窗体分离

TLDR代码。

这就是我要做的。 您说同一页面上有2个控件。 因此,可以由带有TimeVM和MonthVM的引用(成员)的ContainerVM来提供服务。

  1. 每当您执行操作时,TimeVM都会更新后备属性ResultantDate。
  2. ContainerVM已订阅TimeVM.ResultantDate的属性更改的通知。 每当收到更改通知时,它将调用MonthVM.SetMonth()

现在可以在不使用任何视图的情况下(仅在演示者级别)对其进行测试。

感谢您的输入。 我提到了MVP快速入门http://msdn.microsoft.com/en-us/library/ff650240.aspx Model can raise events 我认为,我应该采用这种方法。 任何想法都欢迎。

另外,我已经发布了http://forums.asp.net/t/1760921.aspx/1?Model+View+Presenter+Guidelines来收集有关MVP的一般规则。

引用

开发可以与View和Model进行通信的Presenter。 演示者可能仅具有视图界面的知识。 即使具体视图发生变化,也不会影响演示者。

在具体视图中,控件的事件处理程序将仅调用演示者方法或引发演示者将已订阅的事件。 不应以具体的视图编写表示规则/逻辑。

演示者应仅具有模型的接口对象; 不是具体的模型。 这是为了便于单元测试

视图可以引用业务实体。 但是,不应编写与实体对象相关联的逻辑。 它可能只是将实体对象传递给演示者。

视图接口应该是一个抽象。 它不应具有任何控件或System.Web参考。 具体而言,接口定义的方法除外。

“模型”从不了解具体视图以及界面视图

“模型”可以定义和引发事件。 演示者可以订阅这些由模型引发的事件。

演示者中的公共方法应该是无参数的。 视图对象应仅访问演示者的无参数方法。 另一个选项是视图可以定义演示者可以订阅的事件。 无论哪种方式,都不应传递参数。

由于模型具有所有必需的值(要存储回数据库中),因此无需(大部分时间)将任何值从视图传递给模型。 例如,当在下拉列表中选择一项时,只需将控件的当前索引传递给模型。 然后模型知道如何获取相应的域值。 在这种情况下,视图无需将任何内容传递给演示者。 演示者知道如何从视图中获取价值。

视图可以直接使用模型(不使用演示者)。 例如ObjectDataSource的SelectMethod。 但是控制器从不知道具体视图和接口视图。

演示者引用视图接口,而不是视图的具体实现。 这允许您在运行单元测试时用模拟视图替换实际视图。

我没有使用ASP.net的经验,但是我想我遵循您尝试做的事情的要旨。

似乎通过为单个UI元素创建演示者,可以与演示者精通一个层次。 在这种情况下,月份和时间。 我将其更多地视为ShowTime时期。 ShowTime可以显示月份和时间。

将此与MVP一起使用。 然后,您将需要该页面将实现的IShowTimeView。 (不是控件)。 然后编写一个使用IShowTimeView发送和检索值的ShowTimePresenter。

您将让ShowTime实现IShowTimeView接口。 它将诸如时间,AddDay事件和月份之类的项目往返于页面上的实际控件。

因此,如果我了解您的文章。 事件的顺序将是这样的。

用户输入要添加的天数。 用户单击添加天数“添加天数”会触发该事件,该事件会在“当前”上调用一个方法来添加天数。 演示者中添加天数的方法将进行计算和其他所需的步骤。 然后,add days方法将使用Presenter中的View指针来告诉视图以计算的值更新Month。 然后,视图将采用在控件上设置正确属性的计算值。

要进行单元测试,您需要制作一个实现IShowTimeView的模拟对象,并使用它代替实际的页面对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM