事件冒泡和 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 控件中的数据绑定进行扩展的答案。
注意:视图可以完全独立于演示者吗?
注意:这里每个用户控件都是单独的视图
注意:同一个演示者可以有多个视图(例如根据用户的权限为不同的用户提供不同的控件?)
指南
--COMPLETE代码--
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 - 视图应该能够调用直接演示者方法还是应该始终引发事件?
为什么演示者附加到视图事件而不是视图在大多数 ASP.NET MVP 实现中调用 Presenter 方法?
ASP.NET Web 窗体 - 模型视图演示器和用户控件 control
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
--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 - Should the Presenter use Session?
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
代码太长了。
我就是这样做的。
你说同一页面上有2个控件。因此,可以通过具有 TimeVM 和 MonthVM 的引用(成员)的 ContainerVM 来提供服务。
现在可以在不使用任何视图的情况下进行测试 - 纯粹在演示者级别。
TLDR the code.
Here's how I would do it.
You say there are 2 controls on the same page. So that can be served by a ContainerVM with references (members) of TimeVM and MonthVM.
This can now be tested without using any views - purely at the presenter level.
感谢您的投入。我提到了 MVP 快速入门 http://msdn.microsoft.com/en-us/library /ff650240.aspx。
模型可以引发事件
。我想,我应该采用这种方法。欢迎任何想法。另外,我发布了 http://forums.asp。 net/t/1760921.aspx/1?Model+View+Presenter+Guidelines 收集 MVP 的一般规则。
引用
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
我对 ASP.net 没有经验,但我想我遵循了你想要做的事情的要点。
看来您要通过为各个 UI 元素制作演示者来提高演示者的水平。在本例中为月份和时间。我更愿意将其视为 ShowTime 时期。 ShowTime 能够显示月份和时间。
与 MVP 一起使用。然后您将需要页面将实现的 IShowTimeView。 (不是控件)。然后编写一个使用 IShowTimeView 发送和检索值的 ShowTimePresenter。
您将使 ShowTime 实现 IShowTimeView 接口。它将时间、AddDay 事件和月份等项目路由到页面上的实际控件或从页面上的实际控件路由这些项目。
所以如果我理解你的文章。事件的顺序大概是这样的。
用户输入要添加的天数。
用户单击添加天数
添加天数会触发调用 Present 上的方法来添加天数的事件。
演示者中添加天数的方法将进行计算和其他所需的步骤。
然后,add days 方法将使用 Presenter 中的视图指针告诉视图使用计算值更新月份。
然后,视图将采用计算值在控件上设置正确的属性。
要进行单元测试,您需要创建一个实现 IShowTimeView 的模拟对象,并使用它来代替实际的页面对象。
I am not experienced with ASP.net but I think I follow the gist of what you are trying to do.
It appears that you are going down to fine a level with your presenter by making presenters for the individual UI elements. In this case the Month and the Time. I would think of it more as ShowTime period. ShowTime has the capability of showing the Month and Time.
To use this with MVP. Then you will need a IShowTimeView that the page will implement. (Not the controls). And then write a ShowTimePresenter that uses IShowTimeView to send and retrieve values.
You will have ShowTime implement the IShowTimeView interface. It will route items like the Time, AddDay events, and the Month to and from the actual controls on the page.
So if I understand your writeup. The sequence of event would be something like this.
The user types in the days to add.
The user clicks add days
Add Days fires the event which calls a method on the Present to add days.
The method in the presenter that add days will make it's calculation and other needed steps.
The add days method will then use the View pointer in the Presenter to tell the view to update the Month with the calculated value.
The View will then take the calculated value set the correct property on the control.
To do unit testing you need to make a mock object implementing IShowTimeView and use that in place of the actual page object.