惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Security Latest
Security Latest
Simon Willison's Weblog
Simon Willison's Weblog
O
OpenAI News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
Arctic Wolf
T
Tor Project blog
G
GRAHAM CLULEY
I
InfoQ
博客园_首页
IT之家
IT之家
The Register - Security
The Register - Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
The GitHub Blog
The GitHub Blog
Blog — PlanetScale
Blog — PlanetScale
N
Netflix TechBlog - Medium
K
Kaspersky official blog
博客园 - 三生石上(FineUI控件)
S
SegmentFault 最新的问题
U
Unit 42
PCI Perspectives
PCI Perspectives
量子位
P
Palo Alto Networks Blog
S
Securelist
T
Troy Hunt's Blog
博客园 - 【当耐特】
Recorded Future
Recorded Future
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
S
Security Affairs
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
博客园 - 聂微东
罗磊的独立博客
N
News and Events Feed by Topic
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
NISL@THU
NISL@THU
C
Cisco Blogs
T
Threatpost
有赞技术团队
有赞技术团队
Forbes - Security
Forbes - Security
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
T
The Exploit Database - CXSecurity.com
Cloudbric
Cloudbric
Cyberwarzone
Cyberwarzone
Google DeepMind News
Google DeepMind News
C
Cyber Attacks, Cyber Crime and Cyber Security

博客园 - ji yang

页面点击分析工具设计与实现 使用FreeMind代替PowerPoint做演示 Velocity 2011大会归来 通过扩展属性为SqlServer的索引添加注释信息 memcached对中文key的支持 更安全的服务器:Windows账号权限修改监控 网站活跃用户统计的思路与设计 以服务的方式提供站点基础功能支持 safari的url地址转义问题 fastdfs dotnet 客户端发布 go lang web项目的部署与发布 从设计图到HTML页面时的注意点 关于加班 关于Google App Engine 一个简单的Spring.net绑定例子 SOA中国路线图活动感受 文章被转载了 产品营销上的求同策略
Asp.net中基类页的设计和使用
ji yang · 2007-08-24 · via 博客园 - ji yang


Asp.net中基类页的设计和使用

在Asp.net业务系统的开发过程中,为了保证页面风格的一致性以及减少重复代码的编写,我们需要引入基类页的概念,即:定义一个基类页,让所有的页面都继承这个基类,并在该基类页中加入公用的属性和方法。

实际使用时,按照功能页面划分,可以定义多个基类页,如:
class FormBase
class BizFormBase   :FormBase 
class ViewFormBase  : BizFormBase 
class EditFormBase  : BizFormBase 
class QueryFormBase : FormBase

FormBase:基类页中的根,提供与业务无关的服务,如:URL重写,日志等。
BizFormBase:加入和业务相关的属性,如:该页面的当前业务对象ID等。
ViewFormBase,:EditFormBase:实现具体的查看,编辑功能。
QueryFormBase:实现对通用查询页面的封装。

从面向对象的角度看,基类页与普通的基类,继承类设计其实区别并不大,都要在基类中编写公用的属性方法,并通过虚函数、事件等方式让继承类重写或响应。所不同的是基类页的设计过程受到所在环境的约束。在WinForm环境下,我们可以预先定义好窗体的公用元素,如工具条,默认的表格以及DataSource控件等。而到了Asp.net下的WebForm,则无法实现界面一级的继承,同时加入了状态管理等要求。

为了帮助大家理解,我们以查询基类页的设计过程来分析:

一个最简单的查询页面会包括三部分,多个查询条件文本框,查询按钮,以及表格。同时查询页会和一个数据访问组件关联,当点查询时,会把查询条件转成where语句提交给数据访问组件。

QueryPeopleForm
OnQueryButtonClick()
{
    string peopleName = txtPeopleName.Text;
    string peopleAge  = txtPeopleAge.Text;
 
    string sql;
    sql = string.Format(“Name Like‘%{0}%’and Age = {1}, PeopleName, peopleAge);
 
     PeopleManager manager = new PeopleManager();
     this.gridMain.DataSource = manager.GetDataTable(sql);
     this.gridMain.DataBind();
}

当点击查询按钮时,我们做了以下三件事:
1 获取查询条件
2 提交查询
3 将查询结果绑定到表格

这儿的提交查询和绑定在不同的查询页面都是一样的,于是我们首先把2,3放到基类页中,并提供这样一个方法:void QueryAndBind(IManager manager, string sql);这儿要定义IManager接口,让所有的Manager都实现该接口,这样基类页就无需知道具体的Manager,只要调用IManager.GetDataTable方法,然后绑定表格到即可。

使用基类页后的代码:

QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
    string peopleName = txtPeopleName.Text;
    string peopleAge = txtPeopleAge.Text;
    sql = string.Format(“Name Like‘%{0}%’and Age = {1}, PeopleName, peopleAge);
    QueryAndBind(new PeopleManager(), sql);
}

这儿的代码少了,但仍有问题,当查询条件变化后,每次拼查询语句的工作即枯燥又容易出错,那么我们加入一个Query类,以简化这儿的操作:

public enum QueryOperator
{
    //等于比较。
    Equal = 0,
    // 不等于
    NotEqual = 1,
    // Like比较
    Like = 6
}

class Query

    void Add(string fieldName, string value, QueryOperator oper);
    string GetSql();
}

QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
    Query query = new Query();
    query.Add(“Name”, txtPeopleName.Text, QueryOperator.Like);
    query.Add(“Age”, txtPeopleAge.Text, QueryOperator.Equal);
    QueryAndBind(new PeopleManager(), query.GetSql());
}

把拼Sql的工作放在Query类中做,调用者只要声明查询字段,对应的值,和比较类型即可。

到这一步,我们的基类页已经很好用了,但还有一个小问题,也就是前面说的,在WebForm中无法实现界面级的继承,那么基类页的QueryAndBind方法,将无法知道查询结果要绑定到哪一个表格,这时我们的做法是在基类页中声明DefaultGrid属性,让继承页来告知当前的表格控件。

修改后的代码:
QueryPeopleForm : QueryFormBase
OnQueryButtonClick()
{
    InitControls(gridMain);
    Query query = new Query();
    query.Add(“Name”, txtPeopleName.Text, QueryOperator.Like);
    query.Add(“Age”, txtPeopleAge.Text, QueryOperator.Equal);
    QueryAndBind(new PeopleManager(), query.GetSql());
}

至此,基类页的功能已经完整了,但仍然不够,如果我们以后想改变查询按钮点击的行为,比如查询结果为空时,要弹出对话框提示,这时仍然要到处修改页面代码,这不是我们所希望的,于是我们将QueryButton的OnClick操作也放在基类页了中执行,继承页只要初始化数据访问组件和设置查询条件即可。

QueryPeopleForm : QueryFormBase
void Initialize()
{
    // 指定页面对应的Manager
    Manager = new PeopleManager();
    // 绑定控件
    InitControls(gridMain, btnQuery);
}

void GetQueryInfo(Query query)
{
    //获得查询条件
    query.Add(“Name”, txtPeopleName.Text, QueryOperator.Like);
    query.Add(“Age”, txtPeopleAge.Text, QueryOperator.Equal);
}

QueryFormBase:

private IManager manager = null;
public IManager Manager
{
    get { return manager; }
    set { manager = value; }
}

void InitControls(GridView grid, Button queryButton)
{
    this.defaultGrid = grid;
    this.queryButton = queryButton;
    queryButton.Click += new EventHandler(QueryButton_Click);
}

void QueryButton_Click(object sender, EventArgs e)
{
    Query query = new Query();
    GetQueryInfo(Query);
    QueryAndBind(manager, query.GetSql());
}

总的代码可以从附件中下载,大家可以加入断点,看看基类,继承类页的代码执行顺序。
应该说基类的设计相对复杂,但好处是继承页的代码变得清楚了,没有多余重复的代码。

而基类页的设计其实是有技巧的,总结起来有以下几条:
1 首先以最直接的方式写出页面代码
2 提取公用方法和添加辅助类
3 提取事件处理流程到基类页中
4 在基类页中设计需要继承页重载的方法与事件

从设计上来讲,用基类页的方式来统一操作、简化页面代码是一种非常直观的方式,缺点是随着项目的演化,基类页会变得大而全,不容易被新的项目重用,这时我们就可以考虑把其中的一部分功能放到用户控件和自定义组件中来实现,以减少耦合性和提高重用性。

代码示例: /Files/jiyang/QueryFormDemo.rar