概述
在Web Client Software Factory系列(3):View-Presenter模式中提到,表示器包含了响应用户事件逻辑以及一些View的状态等,在Web Client Software Factory中包含了一个名为ObjectContainerDataSource的数据源控件,它为View-Presenter模式和数据绑定之间提供了桥梁,ObjectContainerDataSource可以简单的理解为用来包行对象的容器。它的处理过程如下图所示:
下面我们将通过一个完成的实力来演示如何使用View-Presenter模式和ObjectContainerDataSource控件进行数据绑定。按照上一篇所讲的,我们先在Product业务模块下添加一个NewProduct视图。
在视图中添加ObjectContainerDataSource控件
之前请先在工具箱中添加ObjectContainerDataSource控件,位于Microsoft.Practices.Web.UI.WebControls.dll下,拖拽ObjectContainerDataSource控件到NewProduct.aspx页面上。
接下来要做的就是配置ObjectContainerDataSource了,其实要配置也就是DataObjectTypeName属性而已,即ObjectContainerDataSource控件要包含的对象的类型。选择之前我们编写Product实体类,配置完成后ASPX中代码如下:
<asp:Content ID="content1" ContentPlaceHolderID="DefaultContent" Runat="Server"> <h1>NewProduct</h1> <pp:ObjectContainerDataSource ID="ObjectContainerDataSource2" runat="server" DataObjectTypeName="WebClientDemo1.Products.ModuleEntities.Product" /> </asp:Content>
这里配置DataObjectTypeName属性时有两点需要注意:
1.如果实现Insert、Update、Delete操作,所配置的DataObjectTypeName参数所对应的类型要有一个无参的构造函数;
2.如果实现Update、Delete操作,所配置的DataObjectTypeName参数对应的类型要有一个属性能够唯一表示该类型的一个实例,其实就是对应数据库中的主键,也支持联合主键,这个不难理解,想想SQL语句就知道了。
添加DetailsView、GridView绑定到ObjectContainerDataSource
在NewProduct.aspx页面上添加DetailsView、GridView控件,分布指定它们的DataSourceID为ObjectContainerDataSource1,如下图所示:
设置完成后的代码如下:
<asp:Content ID="content" ContentPlaceHolderID="DefaultContent" Runat="Server"> <h1>NewProduct</h1> <hr/> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="Id" DataSourceID="ObjectContainerDataSource1" Width="400px"> <Columns> <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" /> <asp:BoundField DataField="Brand" HeaderText="Brand" SortExpression="Brand" /> <asp:CommandField ShowCancelButton="False" ShowDeleteButton="True" /> </Columns> </asp:GridView> <hr/> <asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False" DataSourceID="ObjectContainerDataSource1" DefaultMode="Insert" Height="50px" Width="400px" DataKeyNames="Id"> <Fields> <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" /> <asp:BoundField DataField="Brand" HeaderText="Brand" SortExpression="Brand" /> <asp:CommandField ButtonType="Button" InsertText=" Add " ShowCancelButton="False" ShowInsertButton="True" /> </Fields> </asp:DetailsView> <pp:ObjectContainerDataSource ID="ObjectContainerDataSource1" runat="server" DataObjectTypeName="WebClientDemo1.Products.ModuleEntities.Product" /> </asp:Content>
实现数据的Insert、Update、Delete
为了实现的数据的增删改,我们需要修改在Web Client Software Factory系列(2):Composite Web应用程序块写过的Service,这里为了演示数据就不从数据库中读取了,而是保存在Session中。
IProductDataService接口:
public interface IProductDataService { Product GetProductById(string id); List<Product> Products { get;set;} void InsertProduct(Product product); void UpdateProduct(Product product); void DeleteProduct(Product product); }
Service实现:
public class ProductDataService : IProductDataService { private List<Product> _products; public List<Product> Products { get { _products = HttpContext.Current.Session["products"] as List<Product>; if (_products == null) { _products = new List<Product>(); } return _products; } set { HttpContext.Current.Session["products"] = value; } } public void InsertProduct(Product product) { product.Id = Guid.NewGuid().ToString(); _products = HttpContext.Current.Session["products"] as List<Product>; if (_products == null) { _products = new List<Product>(); } _products.Add(product); HttpContext.Current.Session["products"] = _products; } public void UpdateProduct(Product product) { Product result = FindProduct(Products, product); if (result != null) { result.Name = product.Name; result.Brand = product.Brand; } } public void DeleteProduct(Product product) { Product result = FindProduct(Products, product); if (result != null) { Products.Remove(result); } } private static Product FindProduct(List<Product> products, Product product) { return products.Find(delegate(Product match) { return product.Id == match.Id; }); } }
打开视图INewProduct,编写如下代码
public interface INewProduct { List<Product> Products { set;} }
并在NewProduct.aspx.cs中实现View接口
public List<Product> Products { set { this.ObjectContainerDataSource1.DataSource = value; } }
接下来我们要做的就是实现Controller,在Web Client Software Factory系列(2):Composite Web应用程序块中注册和使用服务一节中已经讲过了,直接给出代码:
public class ProductsController { public ProductsController() { } private IProductDataService _productDataService; [ServiceDependency] public IProductDataService ProductDataService { set { _productDataService = value; } } public List<Product> Products { get { return _productDataService.Products; } set { _productDataService.Products = value; } } public void InsertProduct(Product product) { _productDataService.InsertProduct(product); } public void UpdateProduct(Product product) { _productDataService.UpdateProduct(product); } public void DeleteProduct(Product product) { _productDataService.DeleteProduct(product); } }
实现我们的Presenter,具体的在Web Client Software Factory系列(3):视图、表示器和控制器中已经讲过
public class NewProductPresenter : Presenter<INewProduct> { private ProductsController _controller; public NewProductPresenter([CreateNew] ProductsController controller) { _controller = controller; } public override void OnViewLoaded() { View.Products = _controller.Products; } public override void OnViewInitialized() { } public void OnProductInserted(Product product) { _controller.InsertProduct(product); } public void OnProductUpdated(Product product) { _controller.UpdateProduct(product); } public void OnProductDeleted(Product product) { _controller.DeleteProduct(product); } }
最后为ObjectContainerDataSource控件添加相关的事件,并具体的操作交给Presenter:
protected void ObjectContainerDataSource1_Inserted(object sender, ObjectContainerDataSourceStatusEventArgs e) { _presenter.OnProductInserted((Product)e.Instance); } protected void ObjectContainerDataSource1_Updated(object sender, ObjectContainerDataSourceStatusEventArgs e) { _presenter.OnProductUpdated((Product)e.Instance); } protected void ObjectContainerDataSource1_Deleted(object sender, ObjectContainerDataSourceStatusEventArgs e) { _presenter.OnProductDeleted((Product)e.Instance); }
这里需要说明的是ObjectContainerDataSourceStatusEventArgs有两个特别重要的属性是Instance和AffectedRows,ObjectContainerDataSource控件通过反射创建它所包含对象的类型的实力Instance,AffectedRows是受影响的行数。
运行后如下:
分页和排序
如果使用ObjectContainerDataSource默认的分页和排序功能,需要设置如下两个属性:
UsingServerPaging="" UsingServerSorting=""
并编写Selecting事件:
protected void CustomersDataSource_Selecting(object sender, ObjectContainerDataSourceSelectingEventArgs e) { _presenter.OnSelecting(e.Arguments.StartRowIndex, e.Arguments.MaximumRows, e.Arguments.SortExpression); }
剩下的就到Presenter中处理分页了:)
结束语
关于Web Client Software Factory中使用View-Presenter模式进行数据绑定和ObjectContainerDataSource控件就到这里了,希望对您有所帮助。
示例代码下载:/Files/Terrylee/WebClientDemo2.rar