今天在研究PetShop里的product.aspx页面,有些地方没看明白,上网搜了一下,发现有以下文章,讲解得比较通俗,转过来慢慢品味
简单明白地讲讲petshop4的多层应用是如何实现的:1)数据怎么取得
简单说,问题是:页面的内容是怎么从数据库中动态产生出来的?而且还是多层的?那些工厂类之类的东西,到底是多层的要素还是技术花招和迷雾?与这个“多层”有多大的关系?一个最简单的多层该是什么样的呢?希望高人能帮我拨开迷雾。
我思考和分析这问题是这样进行的:
在products.aspx文件中,用了母板页和内容页结构。母版页里有 contentplaceholder控件,这可以从工具箱的标准抽屉中拖到设计器上。在内容页(也就是products.aspx了)里,主要就是一个content,是用户定义的,这里又有用户定义的内容控件,叫customlist-productslist。形如:
<asp:Content ID="cntPage" ContentPlaceHolderID="cphPage" runat="Server" EnableViewState="false">
<PetShopControl:ProductsControl ID="ProductsControl1" runat="server" OnLoad="ProductsControl1_Load" />
</asp:Content>
这里是要用这个content去填充母板里的那个contentplaceholder所定的区域。
而内容本身又是从哪里来的呢?内容体是这段:
<PetShopControl:ProductsControl ID="ProductsControl1" runat="server" OnLoad="ProductsControl1_Load" />
这是一个从解决方案资源管理器中拖放出来的东西。具体是将control目录下的productscontrol拖过来就可以了。
好了,这样,我们的问题就集中到productscontrol的设计上了。
我找到controls\productscontrol.ascx,双击它,来研究它在设计器和源编辑器中的样子。
在设计器中,看到一个customlist-productslist,这个东西也该算控件吧,不过在工具箱中是没有的,算用户控件吧。试图找到一个可以拖放它的方法,未果。那么它是怎么跑到设计器上去的呢?
暂时放下它是怎么跑到设计器上的这个问题,先看看它到底是个什么东西。
在设计器上,看其属性,是petshop.web.customlist,这像是个用户定义的类或者说组件。右键点它,在快捷菜单上有几个可能有点击价值的选项:查看代码、查看组件设计器、编辑模板-项模板。
至于其属性,已经自动显示在属性管理窗口中了。
点‘查看代码’,结果就看到productslist.cs文件内容。和在解决方案资源管理器中双击这个文件一样效果。这里,定义了 productslist的部分内容:public partial class ProductsControl : System.Web.UI.UserControl {
注意这个partial,意思是还有其它定义内容在别的文件里。也就是说,一个类可以五马分尸并放到不同文件里了,据说这样对编程者有若干好处,不知道又没有坏处?这里主要定义了当页号改变时,内容要相应重新从数据库中得到,以及页面加载时,数据是怎么获得的。这两函数是pagechanged()和page_load()。
先不考虑研究pagechanged的问题,集中力量看看page_load的问题。
protected void Page_Load(object sender, EventArgs e) {
this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
}
而这里,引入了一个新玩艺:cachedependency,这是个什么东西?多层应用一定要用这个新式武器吗?原来,这是.net2.0引入的缓存机制。当页面装载时,先看看服务器缓存里有没有需要的东西,这里缓存的可能是装配好了的页面html。
暂时不管它,继续猜测。看这个事件的处理,看不出哪里去取数据了,估计这页面load事件后,紧接着就是pagechanged事件,所以取数据的活包给pagechanged事件处理函数了。
在pagechanged()里:
protected void PageChanged(object sender, DataGridPageChangedEventArgs e) {
//reset index
productsList.CurrentPageIndex = e.NewPageIndex;
//get category id
string categoryKey = Request.QueryString["categoryId"];
//bind data
Product product = new Product();
productsList.DataSource = product.GetProductsByCategory(categoryKey);
productsList.DataBind();
}
在bind data段里,是获取数据的实际工作。看来,这里又用了个新类:product。这个类负责把数据取得。于是我们继续追综product类。
namespace PetShop.BLL
{
public class Product
{
public Product();
public ProductInfo GetProduct(string productId);
public IList<ProductInfo> GetProductsByCategory(string category);
public IList<ProductInfo> GetProductsBySearch(string text);
}
}
这个类玩了个花招,用了IList<>,这个IList就是IndexedList,意思是说可以根据索引访问的列表。
那个尖角括号是说,这里用了泛型,换个熟悉的词,就是模板吧。
public IList<ProductInfo> GetProductsByCategory(string category)看起来有点专家派头啊,用人民大众能听懂的词汇来说呢,就是说:有一个函数叫getproductsbycategory,它的参数是category,它返回的是productinfo作元素的的可索引的列表。既然是列表,就不是一般的数组,数组倒是可以根据索引来访问其元素,但数组不能随意扩展,而IList可以有随意个元素,而且,IList有现成的方法可以用。
好了,回到实际问题,在pagechanged时,发生
productsList.DataSource = product.GetProductsByCategory(categoryKey);这个事情,这样,就把productslist里面的datasource填满了。
然而,我们还需要搞清,这里还有一个productslist类,而这是位什么神仙呢?换句话说,它有什么武功呢?右键点它,转到定义,可惜,对象定义被隐藏。这是什么秘籍?
看productscontrol.ascx文件,里面有:
<PetShopControl:CustomList ID="productsList" runat="server" EmptyText="No products found." OnPageIndexChanged="PageChanged" PageSize="4" RepeatColumns="2" CellPadding="16" CellSpacing="0" Width="500px">
可见这里有ASP.net2的方言。翻译过来就是说:有一个customlist,给它起了个马甲叫productslist。。。晕。这是位customlist神仙。那么,我们去看customlist有什么武功吧。
而customlist就是个纯手工作品了。存在于app_code目录,文件名:CustomList.cs
public class CustomList : DataList {
//Static constants
protected const string HTML1 = "<table cellpadding=0 cellspacing=0><tr><td colspan=2>";
protected const string HTML2 = "</td></tr><tr><td class=paging align=left>";
protected const string HTML3 = "</td><td align=right class=paging>";
。。。。。。。。。
原来,customlist它爹是datalist。datalist它妈可是微软啊,略窥一下datalist的武功:
namespace System.Web.UI.WebControls
{
public class DataList : BaseDataList, INamingContainer, IRepeatInfoUser
{
public const string CancelCommandName = "Cancel";
public const string DeleteCommandName = "Delete";
public const string EditCommandName = "Edit";
public const string SelectCommandName = "Select";
public const string UpdateCommandName = "Update";
。。。。。
凭这些武功,datalist在工具箱-数据抽屉 里有正式工作岗位。它是个可视化控件。
不过,customlist基于datalist添加了些花样,看上面的代码可以看到它用了些html元素当成员。
好了,回到本问题:数据怎么从数据库到内容页的?
基本上是:在products.aspx对应的products.cs文件里,定义了当页面改变时要从数据库里取数据并填充给索引化列表productslist的datasource。
这样就得到了数据。
那么,怎么体现多层呢?哪里有层呢?层和层间如何发生关系呢?另文再述,也十分希望高人对此问题进行回复。
关于如何从数据库中取出数据动态显示到页面,上面只是探讨了其骨架,在customlist-productslist.ascx文件中,那个productslist用户控件,内藏了一些asp代码。右键点它,有编辑项模板 菜单选项,进入后可看到人工录入的<%# Eval("Image") %> src属性。问题是,这个函数是怎么得到值的?