技术开发 频道

NBearV3教程——MVP(Model/View/Presenter)

    Step 3 在website中使用View和Presenter

     3.1 在website工程中,先删除原来的Default.aspx和关联的Default.aspx.cs中的代码,并添加website到ViewInterfaces、PresenterInterfaces和PresenterImpls(其实无需添加对PresenterImpls的引用,而只需要将PresenterImpls.dll复制到website的bin目录,这里为了省区手动复制的过程才增加了它的引用)工程的引用。我们为Default.aspx增加一个DropDownList、一个Button和一个GridView控件如下:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!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>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> Choose a Category:&nbsp;<asp:DropDownList ID="listCategories" runat="server" DataTextField="CategoryName" DataValueField="CategoryID"> </asp:DropDownList> <asp:Button ID="btnLoad" runat="server" OnClick="btnLoad_Click" Text="Load Products in Selected Cateogry" /><br /> <br /> <asp:GridView ID="gridProducts" runat="server"> </asp:GridView> </div> </form> </body> </html>

    3.2 在Default.aspx.cs中,我们需要实现前面定义的ISampleView接口,并使用我们已经定义的SamplePresenter。和使用NBear.IoC 中的ServiceFactory类似,我们可以非常简单的使用NBear.MVP中定义的PresenterFactory类,通过Presenter接口得到其实现。代码如下:

1using System; 2using System.Data; 3using System.Configuration; 4using System.Web; 5using System.Web.Security; 6using System.Web.UI; 7using System.Web.UI.WebControls; 8using System.Web.UI.WebControls.WebParts; 9using System.Web.UI.HtmlControls; 10 11using Entities; 12using ViewInterfaces; 13using PresenterInterfaces; 14using NBear.MVP; 15 16public partial class _Default : System.Web.UI.Page, ISampleView 17{ 18 private ISamplePresenter presenter; 19 20 protected void Page_Load(object sender, EventArgs e) 21 { 22 presenter = PresenterFactory.Create().GetPresenter<ISamplePresenter>(this); 23 if (!IsPostBack) 24 { 25 presenter.GetCategories(); 26 DataBind(); 27 } 28 } 29 30 protected void btnLoad_Click(object sender, EventArgs e) 31 { 32 presenter.GetProductsInCategory(); 33 gridProducts.DataBind(); 34 } 35 36 ISampleView Members#region ISampleView Members 37 38 public int CategoryID 39 { 40 get 41 { 42 if (listCategories.SelectedIndex < 0) 43 { 44 return -1; 45 } 46 else 47 { 48 return int.Parse(listCategories.Items[listCategories.SelectedIndex].Value); 49 } 50 } 51 } 52 53 public Category[] Categories 54 { 55 set 56 { 57 listCategories.DataSource = value; 58 } 59 } 60 61 public Product[] ProductsInCategory 62 { 63 set 64 { 65 gridProducts.DataSource = value; 66 } 67 } 68 69 #endregion 70}

    通过PresenterFactory类的Create()我们就能获得一个PresenterFactory类的singleton实例。通过GetPresenter()方法,传入Presenter的接口作为范型参数,页面自己this作为实现了ISampleView接口的实例的唯一的参数,就能得到需要的Presenter的实现类实例,这个内部的过程是通过NBear.IoC的ServiceFactory实现的,因此,可以和IoC_Adv教程中一样使用基于分布式IoC的Service作为Model。

    我们可以看到,website仅依赖于PresenterInterfaces,Prensenter的具体实现通过IoC以依赖注入方式获得。这样,我们可以方便地仅修改配置文件(无需重新编译)就改变Presenter接口对应的具体的Presenter实现类。

    特别注意,我们在使用SamplePresenter时完全没有指定Model的位置,那么SamplePresenter怎么知道哪个model对应当前的view呢?他会通过IPresenter接口(所有的Presenter需要实现该接口)的TypeOfModel属性返回的type,通过NBear.IoC.Service.ServiceFactory.GetService<type>()从IoC容器中自动获得的。也因此,它自动获得了分布式能力。

    3.3 在Web.config中的castle配置节中,因为我们的程序只需要用到category service,我们可以将product service删掉。但是,我们要在castle配置节中增加ISamplePresenter和SamplePresenter的配置。修改后的Web.config代码如下:

<?xml version="1.0"?> <configuration> <configSections> <section name="entityConfig" type="NBear.Common.EntityConfigurationSection, NBear.Common"/> <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/> </configSections> <entityConfig> <includes> <add key="Sample Entity Config" value="~/EntityConfig.xml"/> </includes> </entityConfig> <castle> <components> <!--You can use standard castle component decleration schema to define service interface impls here--> <component id="category service" service="ServiceInterfaces.ICategoryService, ServiceInterfaces" type="ServiceImpls.CategoryService, ServiceImpls"/> <component id="sample presenter" service="PresenterInterfaces.ISamplePresenter, PresenterInterfaces" type="PresenterImpls.SamplePresenter, PresenterImpls"/> </components> </castle> <appSettings/> <connectionStrings> <add name="Northwind" connectionString="Server=(local);Database=Northwind;Uid=sa;Pwd=sa" providerName="NBear.Data.SqlServer.SqlDbProvider"/> </connectionStrings> <system.web> <compilation debug="true"> <assemblies> <add assembly="System.Transactions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> <add assembly="System.Data.OracleClient, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> <add assembly="System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/></assemblies></compilation> <authentication mode="Windows"/> </system.web> </configuration>

    3.4 运行website并浏览Default.aspx页面,我们就可以看到我们实现的功能了。改变Category的选择,点击按钮就能查看不同的Category下的Products。

    后记

    如果看过其他MVP模式的实现,读者可能会注意到某些区别。在这里的实现中,Presenter不需要知道何时绑定数据,不需要处理事件回调,而只需要负责对view和model进行数据传递、验证和过滤。何时绑定,以及哪些数据在IsPostBack时需要重新载入,哪些数据只需要在页面初次载入时载入都是由Default页面自己控制的。这样做的好处是,Presenter对具体的表现层(这里是可以PostBack的页面)没有任何概念上的依赖,做到了真正的解耦。即使要将该Presenter和Model应用到WindowsForm或者WPF表现层,也是轻而易举的。

0
相关文章