事件气泡和MVP:ASP.NET

本文关键字:ASP NET MVP 气泡 事件 | 更新日期: 2023-09-27 18:20:17

我正在努力学习MVP

它在ASP.NET中使用web窗体。我有两个用户控件CurrentTimeView.ascx和MonthViewControl.ascx。CurrentTimeView显示时间。在同一控件中有一个用于添加天数的文本框。新得到的日期称为"结果日期"。当点击按钮添加天数时,会引发一个事件"myBtAddDaysClickedEvent"。

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

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

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

注意:虽然这是一个简单的例子,但我希望在GridView控件中使用MVP和验证机制对数据绑定给出scalablt的答案。

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

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

注意:同一演示者是否可以有多个视图(比如根据其权限为不同用户提供不同的控件?)

指南

  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-视图应该能够直接调用演示者方法,还是应该总是引发事件?

MVP事件或财产

MVP-事件中的模型

MVP-演示者应该使用Session吗?

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

公共方法或订阅查看事件

MVP模式,一个演示者有多少浏览量?

MVP和UserControls以及调用

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

限制违反体系结构-asp.net MVP

表示层中的控制修改

将视图、演示文稿和ASP.NET Web窗体解耦web表单

事件气泡和MVP:ASP.NET

TLDR代码。

以下是我的做法。你说同一页上有两个控件。因此,它可以由具有TimeVM和MonthVM的引用(成员)的ContainerVM提供服务。

  1. 无论何时,TimeVM都会更新备份属性ResultantDate
  2. ContainerVM已订阅TimeVM.ResultantDate的属性更改通知。每当收到更改通知时,它都会调用MonthVM.SetMonth()

现在可以在不使用任何视图的情况下对其进行测试——纯粹是在演示者级别。

感谢您的输入。我推荐MVP Quickstartshttp://msdn.microsoft.com/en-us/library/ff650240.aspx.CCD_ 1。我认为,我应该采用这种方法。欢迎有任何想法。

此外,我还发布了http://forums.asp.net/t/1760921.aspx/1?Model+查看+演示者+指南,收集MVP的一般规则。

报价

开发可以与视图和模型进行通信的Presenter。演示者可能只知道视图界面。即使具体视图更改,不会影响演示者。

在具体视图中,控件的事件处理程序将简单地调用演示者方法或引发演示者将要参加的事件认购。不应写入演示规则/逻辑具体视图。

演示者应该只有模型的接口对象;非混凝土模型这是为了方便单元测试

视图可以引用业务实体。然而,不应该有任何逻辑与实体对象相关联地编写。它可能只是通过实体对象到演示者。

视图接口应该是一个抽象。它不应该有任何控件或System.Web引用。具体地说,不应该有方法,而不是接口定义的方法。

"模型"永远不知道具体的观点以及界面视图

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

演示程序中的公共方法应该是无参数的。查看对象应该只访问演示者的无参数方法。另一种选择is视图可以定义演示者可以订阅的事件。任何一个这样,就不应该有参数传递。

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

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

演示者引用视图界面,而不是视图的具体实施。这允许您替换实际视图在运行单元测试时使用mock视图。

我对ASP.net没有经验,但我认为我遵循了您尝试做的要点。

通过为各个UI元素制作演示者,您似乎要对演示者进行改进。在这种情况下是月份和时间。我更认为它是ShowTime时期。ShowTime具有显示月份和时间的功能。

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

您将让ShowTime实现IShowTimeView接口。它将在页面上的实际控件之间路由Time、AddDay事件和Month等项目。

所以,如果我理解你的文章。事件的顺序应该是这样的。

用户键入要添加的天数。用户单击"添加天数"Add Days触发事件,该事件调用Present上的方法来添加天数。演示者中添加天数的方法将进行计算和其他所需步骤。然后,add-days方法将使用Presenter中的View指针来告诉视图使用计算值更新Month。然后,视图将获取计算值并在控件上设置正确的属性。

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