我正在尝试学习MVP
它在ASP.NET中使用Web表单。我有两个用户控件CurrentTimeView.ascx和MonthViewControl.ascx。CurrentTimeView显示时间。有一个文本框可在同一控件中添加日期。新获得的日期称为“结果日期”。单击按钮添加天数时,将引发一个事件“ myBtnAddDaysClickedEvent”。
在MonthViewControl上,有一个标签显示“结果日期”的月份。目前,我正在为变量“ monthValueToPass”设置一个样本值(因为我不知道如何正确执行)。 如何设置monthValueToPass变量的值以使其符合MVP模型?
string monthValueToPass = "TEST"; monthPresenter.SetMonth(monthValueToPass);
期望创建易于执行单元测试并且不违反MVP架构的MVP。
注意:尽管这是一个简单的示例,但我期望使用MVP和验证机制对GridView控件中的数据绑定有答案。
注意:视图可以完全独立于演示者吗?
注意:每个用户控件在这里都是单独的视图
注意:同一演示者是否可以有多个视图(例如,基于其权限的不同用户的不同控件?)
指导方针
-完整代码-
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窗体分离
感谢您的输入。我提到了MVP快速入门http://msdn.microsoft.com/en- us/library/ff650240.aspx。Model can raise events。我认为,我应该采用这种方法。任何想法都欢迎。
Model can raise events
另外,我已经发布了 http://forums.asp.net/t/1760921.aspx/1?Model+View+Presenter+Guidelines来收集有关MVP的一般规则。
引用
开发可以同时与View和Model通信的Presenter。演示者可能仅具有视图界面的知识。即使具体视图发生变化,也不会影响演示者。 在具体视图中,控件的事件处理程序将仅调用演示者方法或引发演示者将已订阅的事件。不应以具体的视图编写表示规则/逻辑。 演示者应仅具有模型的接口对象;不是具体的模型。这是为了便于单元测试 视图可以引用业务实体。但是,不应编写与实体对象相关联的逻辑。它可能只是将实体对象传递给演示者。 视图接口应该是一个抽象。它不应具有任何控件或System.Web参考。具体而言,接口定义的方法除外。 “模型”从不了解具体视图以及界面视图 “模型”可以定义和引发事件。演示者可以订阅这些由模型引发的事件。 演示者中的公共方法应该是无参数的。视图对象应仅访问演示者的无参数方法。另一个选项是视图可以定义演示者可以订阅的事件。无论哪种方式,都不应传递参数。 由于模型具有所有必需的值(要存储回数据库中),因此无需(大部分时间)将任何值从视图传递给模型。例如,当在下拉列表中选择一项时,只需将控件的当前索引传递给模型。然后模型知道如何获取相应的域值。在这种情况下,视图无需将任何内容传递给演示者。演示者知道如何从视图中获取价值。 视图可以直接使用模型(不使用演示者)。例如ObjectDataSource的SelectMethod。但是控制器从不知道具体视图和接口视图。 演示者引用视图接口,而不是视图的具体实现。这允许您在运行单元测试时用模拟视图替换实际视图。
开发可以同时与View和Model通信的Presenter。演示者可能仅具有视图界面的知识。即使具体视图发生变化,也不会影响演示者。
在具体视图中,控件的事件处理程序将仅调用演示者方法或引发演示者将已订阅的事件。不应以具体的视图编写表示规则/逻辑。
演示者应仅具有模型的接口对象;不是具体的模型。这是为了便于单元测试
视图可以引用业务实体。但是,不应编写与实体对象相关联的逻辑。它可能只是将实体对象传递给演示者。
视图接口应该是一个抽象。它不应具有任何控件或System.Web参考。具体而言,接口定义的方法除外。
“模型”从不了解具体视图以及界面视图
“模型”可以定义和引发事件。演示者可以订阅这些由模型引发的事件。
演示者中的公共方法应该是无参数的。视图对象应仅访问演示者的无参数方法。另一个选项是视图可以定义演示者可以订阅的事件。无论哪种方式,都不应传递参数。
由于模型具有所有必需的值(要存储回数据库中),因此无需(大部分时间)将任何值从视图传递给模型。例如,当在下拉列表中选择一项时,只需将控件的当前索引传递给模型。然后模型知道如何获取相应的域值。在这种情况下,视图无需将任何内容传递给演示者。演示者知道如何从视图中获取价值。
视图可以直接使用模型(不使用演示者)。例如ObjectDataSource的SelectMethod。但是控制器从不知道具体视图和接口视图。
演示者引用视图接口,而不是视图的具体实现。这允许您在运行单元测试时用模拟视图替换实际视图。