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

推荐订阅源

P
Palo Alto Networks Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
CERT Recently Published Vulnerability Notes
C
Cybersecurity and Infrastructure Security Agency CISA
S
Schneier on Security
S
Securelist
酷 壳 – CoolShell
酷 壳 – CoolShell
C
CXSECURITY Database RSS Feed - CXSecurity.com
Cyberwarzone
Cyberwarzone
Apple Machine Learning Research
Apple Machine Learning Research
S
SegmentFault 最新的问题
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
GbyAI
GbyAI
Security Latest
Security Latest
Last Week in AI
Last Week in AI
Microsoft Security Blog
Microsoft Security Blog
云风的 BLOG
云风的 BLOG
Recorded Future
Recorded Future
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
TaoSecurity Blog
TaoSecurity Blog
C
Cisco Blogs
博客园 - 【当耐特】
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
B
Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Attack and Defense Labs
Attack and Defense Labs
The Last Watchdog
The Last Watchdog
U
Unit 42
阮一峰的网络日志
阮一峰的网络日志
Project Zero
Project Zero
WordPress大学
WordPress大学
L
LINUX DO - 最新话题
F
Fortinet All Blogs
L
LINUX DO - 热门话题
PCI Perspectives
PCI Perspectives
Simon Willison's Weblog
Simon Willison's Weblog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
MongoDB | Blog
MongoDB | Blog
Latest news
Latest news
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
The Hacker News
The Hacker News
爱范儿
爱范儿
O
OpenAI News
J
Java Code Geeks
T
The Exploit Database - CXSecurity.com
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - 春鱼

在文档中正确地使用中英文 文档还是程序? Smart Document 技术概述 拟成立Office团队 实现类型化的数据绑定(列表)控件 数据与操作的分离、数据实体设计及零、一与多(单体与集合)的辨证统一 推荐一个关于"架构"的演示文稿(PPT) 设计一个 validatable control(可校验控件)、兼论“三级联动” 浅论taglib设计 HTC 编程思想 ASP后遗症种种 录友人一曲清歌 log4net 配置与应用 Visual SourceSafe应用守则 应用程序设计/命名及编码规范方案 TreeView穿新衣: 以优雅的名义 回忆一支有意境的老歌... 列表和分页器之间的对话 统一、标准、扩展:模块间数据传送实践 Custom Control 设计初论
重新画差不多一摸一样的UI? - ASCX的MVC模式实现
春鱼 · 2004-04-08 · via 博客园 - 春鱼

[摘要]
本文论述了如何改善设计,使表层的结构更灵活。

[引言]
前几天, 我在与一个朋友, 他同时是我的技术经理,谈到我所设计的ASCX基本实现了MVC的时候, 他好像显得特别不以为然。他说ASP.NET本来就是MVC分开的。ASPX就是V,而CODE BEHIND就是C,数据库就是M。我想他没有真正理解我的意思。

确切地说我也不清楚自己到底有没有正确理解MVC。我想如果要像理解数学或者几何原理一样理解也不是必要的。能够解决实际问题的、灵活的、易于维护的设计就是好的设计。

[实例]
为了更明白地说明问题,或者为了减小篇幅,我引入一个实际应用中非常普遍的需求:管理会员。每个会员到系统中注册,我们想尽可能知道他的资料。我们需要一个模块来管理会员的基本资料,诸如姓名,年龄,个人爱好,联系办法种种。我们需要收集这些资料,管理员需要查询这些资料,用户自己也许会修改这些资料。这其中必须我们提供数个界面来协助用户操作。

V
这里的V是ASCX构图。大家都知道ASCX即可以显示HTML,又可以直接查询数据库,又可以做计算。可以包容任何服务器端控件。但是好的设计的原则是“高内聚,低耦合”,ASCX归根到底是一个类。我们不能设计得让它无所不能,或者说让它知道我们太多业务上的逻辑。比如数据库是如何设计的, 底层类都有那些方法。一种对象,不管其内部逻辑多复杂,其公开的特性或者方法越少越好,越常规越好。那么我们给ASCX都设计什么功能呢?

这里,我们将ASCX看作消极的显示数据的”白板“。仅仅被动到通过控制器设置其属性呈现数据。而有关数据的处理一概不管。当然,我们的白板也不见得就是白色的。在格式上还是允许它尽可能玩出花样。对于我们的实例,我们设计了一种ASCX来呈现会员基本资料。MemberInformation.ascx(MemberInformation类)。我们需要给类MemberInformation公开一系列特性。比如我们要求白板上显示姓名,出生日期,电话,电子邮件...,我们就需要给类MemberInformation公开Name, BirthDate, PhoneNumber, EmailAddress等特性。在显示构图方面,我们需要以集中模式将数据呈现出来
1.查询时只读显示
2.新会员登记填空表单
3.会员更改个人资料时的表单
至少会有以上几种情况。这些视图,显示的数据是完全一样的,而表现模式又大大不同。如果我们直接把上述界面制作在ASPX页上,我们不得不设置显示单条数据个一个个服务器对象的值。还有复杂的有效性验证。

将以上视图合一。
既然数据一致,并且多处使用,就有封装的必要。我们将上述视图总结一下,不外乎:以HTML表单形式展示数据,以报表的方式展示(只读)。不论是新登记还是老会员更改资料。我们必须是ASCX这个V层可以以两种方式展现相同的数据方案。

两种表现模式
我们需要以HTML ATTRIBUTE或者编程的方式控制ASCX的表现模式。我们给MemberInformation类设置一个属性:public string PresentationMode.之所以是串类型是因为需要在HTML ATTRIBTE中设置。可选的值有Form,(可输入数据的表单模式),Report模式(只读的报表模式)。这样我们可以像如下的方法控制其表现模式:

<Xxx:MemberInformation ID=MemberInformation1 Runat=Server PresentationMode=Form />
也可以在编程时像如下方法:
this.MemberInformation1.PresentationMode = “Form“;

设置FORM值时,ASCX显示出来就是表单样式了。

如何让ASCX这么听话呢
在ASCX里放置两个<asp:Panel />一个内装一个HTML table, 按照既定的格式排列各个服务器control. 另一个装安排好的form elements. 呈现时(一般是Page_Load控制)检查自己的PresentationMode值,如果是form就显示第一个panel, 隐藏第二个。如果设置为Report则相反。这样看起来ASCX就可以切换界面了。
代码范例(实际项目摘取)

  /// <summary>
  /// 关键特性: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 
  /// Form: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  /// Report: xxxxxxxxxxxxxxxxxxxxxxxx
  /// 缺省值: Form
  /// </summary>
  private string representationMode = "Form";
  public string RepresentationMode
  {
   get
   {
    return this.representationMode;
   }
   set
   {
    this.representationMode = value;
    if(value == "Form")
    {
     this.FormPanel.Visible = true;
     this.ReportPanel.Visible = false;
    }
    else
    {
     this.FormPanel.Visible = false;
     this.ReportPanel.Visible = true;
    }
   }
  }

与公开的特性连接
公开的特性是其控制器访问或设置视图的数据的接口。一般通过编程进行设置。既然是公开的特性就必须有get,set访问器。这些特性的访问器必须即可以设置到report的数据,又可以访问到form的数据。总之,特性访问器一般必须很清楚地知道管姓名的是哪两个,管年龄的又是哪两个。这样,我们只需设定MemberInformation1.Name = “Jay Xu“, MemberInformation1.Age = 23就可以了。 而不用管显示姓名的控件被安排在什么地方,名称或ID是什么。

特性有关代码范例(实际项目摘取)

  /// <summary>
  /// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  /// xxxxxxxxxxxxxxxxxxxxxxxx
  /// </summary>
  public string Name
  {
   get
   {
    return this.NameBox.Text;
   }
   set
   {
    this.NameBox.Text = value;
    this.NameLabel.Text = value;
   }
  }

数据模型统一。
这里的M,其实是一系列常规值的组合。例如姓名(字符串),年龄(整型),出生年月日(日期)等。在作者实际的项目中,数据实体是一组派生自DataSet的强类型化了的对象。所以并没有将这些数据打包成一个类。

控制器
控制器是管理ASCX的容器。对MemberInformation的数据进行写入,读出的工作。设计到数据是怎么从数据库到前端来的,还有数据是如何持久化到数据库中去的,都是控制器应该操心的事情了。我们的V只管显示数据,还有听从安排切换模式。

[进一步增强]
在get, set访问器中进行有效性校验。例如日期的有效性。可以在get访问过程中进行计算。如果出错,可以选择抛出异常,或者以某种形式通知用户。这些逻辑都应该隐藏在ASCX。
为适应不同场合需求,可以给ASCX增加多个用于控制样式的特性。例如背景色,字体,等等。

[需要注意的问题]
如果某些值是通过在有限项中选择得到的, 则应通过一定途径给选择控件赋初值。如果某些值是多项选择的,则应以合适的数据类型表现其值,比如数组。
在使用编程的方式切换显示模式时注意应使控件的EnableViewState属性为true.(缺省值就是true, 只要你不显示地关闭它)。

[设计思想上的扩充]
可以将这个设计思路应用到其他类型的ASCX上. 比如用于显示List(名单)样式的数据时. 可以把已经设计好的Repeater或者DataGrid包装成一个ASCX.

如果你明白了本文意图, 你可以在你的下一个项目中尝试一下, 编码的工作量可能会稍微增加, 但是除了可以很好的解决当前的问题外, 在一定程度上使设计工作更灵活, 更优雅, 并且带来重用的可能. 也能为将来的项目提供帮助.