事件冒泡和 MVP:ASP.NET [英] Event Bubbling and MVP: ASP.NET

查看:26
本文介绍了事件冒泡和 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. 模型视图演示者 - 指南

--完整代码--

使用系统;公共接口 ICurrentTimeView{//属性视图日期时间 当前时间{放;}//查看方法无效AttachPresenter(CurrentTimePresenter演示者);}使用系统;公共接口 IMonthView{//属性视图字符串月份名称{放;}//查看方法//查看界面知道presenter无效AttachPresenter(MonthPresenter演示者);}使用系统;公共类 CurrentTimePresenter{私有 ICurrentTimeView 视图;//prsenter 的构造函数公共 CurrentTimePresenter(ICurrentTimeView inputView){如果(输入视图 == 空){throw new ArgumentNullException("视图不能为空");}}this.view = inputView;}//Presenter中定义的方法public void SetCurrentTime(bool isPostBack){如果 (!isPostBack){view.CurrentTime = DateTime.Now;}}//Presenter中定义的方法public void AddDays(string daysUnparsed, bool isPageValid){如果(isPageValid){view.CurrentTime = DateTime.Now.AddDays(double.Parse(daysUnparsed));}}使用系统;公开课 MonthPresenter{私人 IMonthView 月视图;//prsenter 的构造函数公共 MonthPresenter(IMonthView inputView){如果(输入视图 == 空){throw new ArgumentNullException("视图不能为空");}this.monthView = inputView;}//Presenter中定义的方法//presenter 如何决定需要的值.公共无效SetMonth(字符串monthValueInput){如果 (!String.IsNullOrEmpty(monthValueInput)){月视图.月名 = 月值输入;}别的{}}}

用户控制 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"/>使用系统;使用 System.Web.UI;公共部分类 Views_CurrentTimeView : UserControl, ICurrentTimeView{//1.除了用于附加演示者的视图定义方法外,用户控件没有其他方法//2.属性只有设置方法私人 CurrentTimePresenter 演示者;//代表公共委托无效 OnAddDaysClickedDelegate(string strValue);//事件公共事件 OnAddDaysClickedDelegate myBtnAddDaysClickedEvent;//用于从aspx页面获取用户控件中的演示者.public void AttachPresenter(CurrentTimePresenter 演示者){如果(演示者 == 空){throw new ArgumentNullException("presenter 不能为空");}this.presenter = 主持人;}//实现视图的属性公共日期时间当前时间{放{//在设置属性时,设置控件的值lblCurrentTime.Text = value.ToString();}}//用户控件中的事件处理程序protected void btnAddDays_OnClick(object sender, EventArgs e){如果(演示者 == 空){throw new FieldAccessException("presenter null");}//要求presenter做它的功能Presenter.AddDays(txtNumberOfDays.Text, Page.IsValid);//引发事件if (myBtnAddDaysClickedEvent != null){myBtnAddDaysClickedEvent(string.Empty);}}}

用户控制 2

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

使用系统;使用 System.Web;使用 System.Web.UI;使用 System.Web.UI.WebControls;公共部分类 Views_MonthViewControl : System.Web.UI.UserControl, IMonthView{//1.除了用于附加演示者的视图定义方法外,用户控件没有其他方法//2.属性只有设置方法私人 MonthPresenter 主持人;//从aspx页面设置用户控件中的演示者.public void AttachPresenter(MonthPresenter 演示者){如果(演示者 == 空){throw new ArgumentNullException("presenter 不能为空");}this.presenter = 主持人;}//实现视图的属性公共字符串 MonthName{放{//在设置popert期间,设置控件的值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="服务器"><title>页面标题</title><身体><form id="form1" runat="server"><mvpProject:CurrentTimeView id="ucCtrlcurrentTimeView" runat="server"/><br/><br/><month:MonthView id="ucCtrlMonthView" runat="server"/></表单>使用系统;使用 System.Web.UI;公共部分类 ShowTime : Page{CurrentTimePresenter currentTimePresenter;MonthPresenter monthPresenter;protected void Page_Load(object sender, EventArgs e){HelperInitCurrentTimeView();HelperInitMonth();}私有无效 HelperInitMonth(){//创建演示者monthPresenter = new MonthPresenter(ucCtrlMonthView);//将presenter对象传递给用户控件ucCtrlMonthView.AttachPresenter(monthPresenter);}私有无效 HelperInitCurrentTimeView(){//通过将视图(用户控制)传递给演示者来克里特斯演示者.//用户控件已经实现了IViewcurrentTimePresenter = new CurrentTimePresenter(ucCtrlcurrentTimeView);//将presenter对象传递给用户控件ucCtrlcurrentTimeView.AttachPresenter(currentTimePresenter);//调用presenter动作在用户控件中加载时间.currentTimePresenter.SetCurrentTime(Page.IsPostBack);//用户控件中描述的事件????订阅它.ucCtrlcurrentTimeView.myBtnAddDaysClickedEvent += new Views_CurrentTimeView.OnAddDaysClickedDelegate(CurrentTimeViewControl_AddButtonClicked_MainPageHandler);}void CurrentTimeViewControl_AddButtonClicked_MainPageHandler(string strValue){字符串月值 = "l";monthPresenter.SetMonth("样本值");//myGridCntrl.CurrentCharacter = theLetterCtrl.SelectedLetter;//myGridCntrl.LoadGridValues();}}

一些 MVP 讨论:

模型视图演示者 - 指南

在 MVP 中写验证的地方

MVP- 视图应该能够直接调用演示者方法还是应该总是引发事件?

MVP 事件或属性

MVP 中的模型 - 事件

MVP - 演示者应该使用会话吗?

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

公共方法或订阅查看事件

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

MVP 和 UserControls 和调用

ASP.NET Web Forms - Model View Presenter 和用户控制控件

限制违反架构——asp.net MVP>

表示层中的控制修改

分离视图、演示和 ASP.NET Web 窗体网络表单

解决方案

感谢您的投入.我提到了 MVP 快速入门 http://msdn.microsoft.com/en-us/library/ff650240.aspx.模型可以引发事件.我想,我应该采用这种方法.欢迎提出任何想法.

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

引用

<块引用>

开发可以与视图和模型进行通信的Presenter.Presenter 可能只知道视图接口.即使具体视图更改,不影响presenter.

在具体视图中,控件的事件处理程序将简单地调用演示者方法或引发演示者将拥有的事件订阅了.不应该写有表示规则/逻辑具体视图.

Presenter 应该只有模型的接口对象;不具体模型.这是为了便于单元测试

View 可以引用业务实体.但是应该没有逻辑写与实体对象相关联.它可能只是通过呈现者的实体对象.

视图接口应该是一个抽象.它不应该有任何控件或 System.Web 引用.具体来看,应该没有接口定义方法以外的方法.

模型"从不知道具体视图以及界面视图

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

presenter 中的公共方法应该是无参数的.查看对象应该只访问演示者的无参数方法.另外一个选择视图可以定义演示者可以订阅的事件.任何一个方式,应该没有参数传递.

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

View 可以直接使用模型(不使用 Presenter).例如.ObjectDataSource 的 SelectMethod.但控制器永远不知道具体视图以及界面视图.

presenter 引用视图接口而不是视图的具体实施.这允许您替换实际视图运行单元测试时使用模拟视图.

I am trying to learn MVP

It is using web forms in ASP.NET. I have two user controls CurrentTimeView.ascx and MonthViewControl.ascx. The CurrentTimeView displayes time. There is a textbox to add days in the same control. The newly got date is called "resultant date". When the button is clicked for add days, an event is raised "myBtnAddDaysClickedEvent".

On the MonthViewControl, there is a label that shows the month of the "resultant date". At present I am setting a sample value for the variable "monthValueToPass" (since I don’t know how to do it properly). How do I set the value for monthValueToPass variable to make it comply with MVP model?

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

The expectation is to create MVP that is easy to do Unit Testing and does not violate MVP architecure.

Note: Though this is a simple example, I am expecting an answer scalablt to databinding in GridView control using MVP and validation mechanisms.

Note: Can view be totally independant of presenter?

Note: Each user control is separate views here

Note: Can there be multiple views for same presenter (like different controls for various users based on thier permisssion?)

GUIDELINES

  1. Model View Presenter - Guidelines

--COMPLETE CODE--

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
       {

       }        
    }   
}

User Control 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);
      }
   }     
}

User Control 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

<%@ 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();
    }
}

Some MVP discussions:

Model View Presenter - Guidelines

In MVP where to write validations

MVP - Should views be able to call presenter methods directly or should they always raise events?

MVP events or property

The Model in MVP - Events

MVP - Should the Presenter use Session?

Why do Presenters attach to View events instead of View calling Presenter Methods in most ASP.NET MVP implementations?

Public Methods or subscribe to View events

MVP pattern, how many views to a presenter?

MVP and UserControls and invocation

ASP.NET Web Forms - Model View Presenter and user controls controls

Restrict violation of architecture - asp.net MVP

Control modification in presentation layer

Decoupling the view, presentation and ASP.NET Web Forms web-forms

解决方案

Thanks for the inputs. I referred MVP Quickstarts http://msdn.microsoft.com/en-us/library/ff650240.aspx. Model can raise events. I think, I should go with that approach. Any thoughts are welcome.

Also, I have posted http://forums.asp.net/t/1760921.aspx/1?Model+View+Presenter+Guidelines to collect general rules on MVP.

Quote

Develop Presenter which can communicate with both View and Model. Presenter may only have knowledge of view interfaces. Even if the concrete view changes, it does not affect presenter.

In the concrete view, control’s event handlers will simply call presenter methods or raise events to which presenter would have subscribed. There should be no presentation rule/logic written in concrete view.

Presenter should have only interface object of model; not concrete model. This is for the ease of Unit Testing

View can refer business entities. However there should no logic written associated with the entity objects. It may just pass the entity object to presenter.

View interface should be an abstraction. It should NOT have any control or System.Web reference. In concrete view, there should be no method other than interface defined methods.

The "Model" never knows about the concrete view as well as the interface view

"Model" can define and raise events. Presenter can subscribe these events raised by model.

Public methods in presenter should be parameterless. View object should access only parameterless methods of presenter. Another option is view can define events to which the presenter can subscribe. Either way, there should be no parameter passing.

Since the model has all the required values (to be stored back in database), there is no need to pass any value to model from view (most of the time). E.g. when an item is selected in dropdown list only the controls’ current index need to be passed to model. Then model knows how to get the corresponding domain values. In this case, the view need not pass anything to presenter. Presenter knows how to get value from view.

View may make use of model directly (without using presenter). E.g. ObjectDataSource's SelectMethod. But controller never knows about the concrete view as well as the interface view.

The presenter references the view interface instead of the view's concrete implementation. This allows you to replace the actual view with a mock view when running unit tests.

这篇关于事件冒泡和 MVP:ASP.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆