在做项目的过程中发现很多功能模块中的页面功能极其相似,在做新模块时经常是将上一个模块的页面复制过来,对代码稍做修改即可。
比如项目中要实现两个模块:
块1--厂商信息管理:包括厂商信息新增,厂商信息确认,厂商信息浏览;
块2--原料信息管理:包括原料信息新增,原料信息确认,原料信息浏览;
一般我们会先实现第一个模块,然后在实现第二个模块时尽可能地复制粘贴再做修改以达到快速开发的效果。所以当两个模块实现后会有以下特点:
1.具有相似的页面结构:例如新增时都是页面上部一堆TextBox控件再加下部一个保存和取消按钮;浏览页面都是上面一排有打印、设置查询条件、设置表格样式等功能的按钮,下面一个GridView。
2.页面功能相似:新增页面都是点击“保存”按钮后将用户输入的信息保存到某个数据库表;浏览页面都是跟据某处传来的查询条件去某个数据库查出数据然后绑到GridView上;都是双击GridView中某行打开修改页面。
3.页面呈现的控件个数与类型不同:同样是新增,厂商信息里也许是六个TextBox再加两个DropDownList,而原料信息里则是四个TextBox一个DropDownList再加两个CheckBox。
4.数据库表的操作不同:第一个模块操作的是数据库中的chsh表,第二个则是yuanliao表。同样是“保存”按钮,但Click事件里业务的具体处理不同。
5.页面间传递的参数不同:在厂商信息浏览功能中我们在浏览页面点击“查询条件设置”按钮弹出一页面在上面设置查询条件,确认后此页面将条件保存到Session["chsh_condition"]中,然后原来的浏览页面读这个Session然后给GridView绑数据;而在原料信息浏览功能中为了不与上一个Session冲突我们将条件保存到Session["yuanl_condition"]中,所以在保存查询条件的代码中我们会发现除了这点不同外其它代码几乎一模一样。(PS:这样做主要是因为不能保证用户在关闭窗口时上一个Session被remove掉)
如果用户所要求的功能是一成不变的话,这种复制粘贴的方法没有什么不好,但更多时候用户总是让你今天在页面上加一个按钮,明天让你多放一个输入框。如此一来你不得一个页面一个页面的去修改,等一个页面被多次复制,代码复杂而用户就要明天看到效果时写程序的人就会死的很惨了。
于是我们很想达到这样一种效果:只修改一个页面,用户所看到的所有页面都能改变,而且保证在开发功能相似的模块时仍然具有“复制,粘贴,修改”的效率。
就目前而言我只想到了三种方法:
1.将功能相似的页面抽象为一个类,某个页面一旦继承了这个类就能拥有定义好的元素,如按钮数量、按钮类型,页面布局等。
2.只使用一个页面,然后根据传入的控制信息来决定页面的具体功能。例如:我们写好一个浏览页面,在打开这个页面时我们传递一个“A1B4C3”这样的字符串过去,然后页面根据这个字符串来决定它的GridView的数据是从chsh表还是从yuanliao表中查、它的打印按钮是否显示等。
3.使用母板页或iframe 这种嵌套的方式。
第一种方法具说并不能将UI继承下来;第二种在winform中已经实现,但在webform中如何就不得而知;第三种我目前还没具体实现的思路。
--------------------各位看官你们有什么思路或方法么?
----------------------------------分割线 ----------------------------------
第一种方法的尝试:
首先在App_Code下建一个BasePage类,代码如下:
Code
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
/// <summary>
///BasePage 的摘要说明
/// </summary>
public class BasePage:System.Web.UI.Page
{
protected Control form;
protected Button bt_add;
protected Button bt_query;
protected Button bt_setTable;
protected GridView gd;
public BasePage()
{
}
protected override void OnInit(EventArgs e)
{
this.Load += new EventHandler(BasePage_Load);
this.Error += new EventHandler(BasePage_Error);
this.PreRender += new EventHandler(BasePage_PreRender);
base.OnInit(e);
}
void BasePage_PreRender(object sender, EventArgs e)
{
}
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
}
void BasePage_Error(object sender, EventArgs e)
{
}
void BasePage_Load(object sender, EventArgs e)
{
set_Controls();
}
/*为页面填充必要的控件*/
protected void set_Controls()
{
form = this.FindControl("form_page");
bt_add = new Button();
bt_add.ID = "Button_add";
bt_add.Click += new EventHandler(Button_add_Click);
bt_add.Text = "新增";
bt_query = new Button();
bt_query.ID = "Button_query";
bt_query.Click += new EventHandler(Button_query_Click);
bt_query.Text = "查询";
bt_setTable = new Button();
bt_setTable.ID = "Button_setTable";
bt_setTable.Click += new EventHandler(Button_setTable_Click);
bt_setTable.Text = "设置";
form.FindControl("title_div").FindControl("add_button").Controls.Add(bt_add);
form.FindControl("title_div").FindControl("query_button").Controls.Add(bt_query);
form.FindControl("title_div").FindControl("setTable_button").Controls.Add(bt_setTable);
gd = new GridView();
gd.ID = "GridView1";
gd.DataBinding += new EventHandler(GridView1_DataBinding);
gd.RowCreated +=new GridViewRowEventHandler(GridView1_RowCreated);
gd.RowDataBound+=new GridViewRowEventHandler(GridView1_RowDataBound);
gd.DataBound +=new EventHandler(GridView1_DataBound);
form.FindControl("main_div").FindControl("GridView_div").Controls.Add(gd);
}
/*为GridView绑定数据源,在子类中应该重写该方法。
*/
protected virtual int boundGridViewDataSource()
{
return 1;
}
/*绑定开始时发生
* 事件
*/
protected virtual void GridView1_DataBinding(object sender, EventArgs e)
{
}
/*绑定行被创建时发生
* 事件
*/
protected virtual void GridView1_RowCreated(object sender,EventArgs e)
{
}
/*绑定每一行时发生
* 事件
*/
protected virtual void GridView1_RowDataBound(object sender,EventArgs e)
{
}
/*所有行绑定完成时发生
* 事件
*/
protected virtual void GridView1_DataBound(object sender,EventArgs e)
{
}
/*新增
* 事件
*/
protected virtual void Button_add_Click(object sender, EventArgs e)
{
}
/*查询
* 事件
*/
protected virtual void Button_query_Click(object sender, EventArgs e)
{
}
/*设置表格显示
* 事件
*/
protected virtual void Button_setTable_Click(object sender, EventArgs e)
{
}
}
然后再建一个页面Child_Page1来继承这个类:
Child_page1.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Child_page1.aspx.cs" Inherits="test2_Child_page1" %>
<!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>标题页</title>
</head>
<body>
<form id="form_page" runat="server">
<div id="title_div" runat="server">
<table border="1">
<tr>
<td><div id="add_button" runat ="server"></div></td>
<td><div id="query_button" runat ="server" ></div></td>
<td><div id="setTable_button" runat ="server" ></div></td>
<td><div id="print_button" runat ="server"></div></td>
</tr>
</table>
</div>
<div id="main_div" runat="server">
<table >
<tr>
<td><div id="GridView_div" runat="server"> </div></td>
</tr>
</table>
</div>
<div id="bottom_div" runat ="server" >
<table >
<tr>
<td></td> <td><div id="close_button" runat ="server"></div></td> <td></td>
</tr>
</table>
</div>
</form>
</body>
</html>
public partial class test2_Child_page1 : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
可以看到,我们在Child_page1.aspx中放置了很多runat="server" 的html标签,这样做是为了控制动态生成的控件的位置。然后我们运行看下:
在基类中生成的三个按钮出来了。同样,可以通过重写他们的单击事件处理方法来进行相应的操作。
但这样明显不能满足要求,例如:我们在基类中动态添加了一个Panel,但Panel里面的内容要在子页面继承后才去指定,而在aspx页面上是不可能通过拖拉这种方式放一个控件在Panel中的。所以在子页面cs文件中我们得先获得Panel对象,然后动态生成内容,并将它们Add到Panel中去。至于排板和显示的效果就别提了(上面的三个按钮已经够难看了)。