事件冒泡和MVP:ASP.NET

我正在努力学习MVP

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

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

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

期望是创建易于进行unit testing的MVP,并且不违反MVP架构。

注意:虽然这是一个简单的例子,但我期待使用MVP和validation机制在GridView控件中进行数据绑定的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

  

 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

  

 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

    

页面标题

   

 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中写入validation的位置

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

MVP活动或财产

MVP中的模型 – 事件

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

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

公共方法或订阅查看事件

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。 演示者可能只具有视图界面的知识。 即使具体视图发生变化,也不会影响演示者。

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

Presenter应该只有模型的接口对象; 不是具体的模型。 这是为了便于unit testing

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

View界面应该是一个抽象。 它不应该有任何控件或System.Web引用。 在具体的视图中,除了接口定义的方法之外,应该没有其他方法。

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

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

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

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

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

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

我对ASP.net没有经验,但我认为我遵循你想要做的事情的要点。

通过为各个UI元素制作演示者,您似乎可以与演示者达到一定水平。 在这种情况下,月份和时间。 我会把它想象成ShowTime时期。 ShowTime具有显示月份和时间的function。

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

您将使ShowTime实现IShowTimeView接口。 它会将Time,AddDay事件和Month等项目与页面上的实际控件相关联。

所以,如果我理解你的写作。 事件的顺序就是这样的。

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

要进行unit testing,您需要创建一个实现IShowTimeView的模拟对象,并使用它来代替实际的页面对象。