很多情况下,你并不需要从头开始创建一个新控件。有些功能也许在 ASP.NET 的 Web 控件的基本集合中已经存在了。所有这些控件都是普通类,你可以组合它们(使用其他类的实例来创建一个新类)或者继承它们(扩展一个现存类和改变它的功能来创建一个新类)

组合控件

ASP.NET 提供了这样一个功能,即允许你从其他现存的 Web 控件构建你的控件类。

       基本的技巧是从类 System.Web.UI.WebControls.CompositeControl (它自身继承 WebControl)派生一个新类。然后,必须覆盖 CreateChildControls()方法来添加子控件。此时,你可以创建一个或多个控件对象,设置它们的属性和事件处理程序,最后把它们加入到当前控件的 Controls 集合中。这种方式最大的优点在于你根本不需要定制呈现代码,呈现工作被委托给了作为组成部件的服务器控件,你也不需要担心触发回传和获取回传数据等细节,因为子控件自身会处理这些细节

下面创建一个 TitledTextBox 控件,这个控件组合一个 Lable 和 一个 TextBox:

public class TitledTextBox : CompositeControl
{ ... }

CompositeControl 控件实现了 INamingContainer 接口。这只是个标记接口,没有任何方法,它的作用仅仅是告诉 ASP.NET 保证所有的子控件拥有唯一的 ID 值。(ASP.NET 通过在控件的 ID 之前附加服务器控件的 ID 来实现这一点,这确保了不会有任何命名冲突,即使你的页面拥有不止一个 TitledTextBox 控件实例)。

为了简单起见,应该使用成员变量跟踪构成控件。这使得控件里的任何方法都能方便的访问成员控件。但此时还不应该创建这些控件:

protected Label label;
protected TextBox textBox;

网页无法直接访问这些控件中的任何一个。如果允许访问某个属性,在控件类中必须添加属性:

public string Title
{
    get { return (string)ViewState["Title"]; }
    set { ViewState["Title"] = value; }
}
 
public string Text
{
    get { return (string)ViewState["Text"]; }
    set { ViewState["Text"] = value; }
}

注意:这些属性只是在视图状态里存储信息,而不是直接访问子控件。这是因为子控件也许还不存在。这些属性将会在 CreateChildControls()方法里被应用到子控件上。

所有的控件都在 <span> 标签里被呈现,这样做很有效。这保证了如果网页针对 TitledTextBox 控件使用了 font、color、position 等特性时,所有的子控件都能实现预期的效果。

现在,可以创建子控件对象了。这些对象都独立于另外一个控件对象:LiteralControl ,LiteralControl 仅表现为一小段 HTML 代码,本例中 LiteralControl 包装了两个不换行空格:

protected override void CreateChildControls()
{
    // Add the label.
    label = new Label();
    label.EnableViewState = false;
    label.Text = Title;
    Controls.Add(label);
 
    // Add a space
    Controls.Add(new LiteralControl("&nbsp;&nbsp;"));
 
    // Add the text box.
    textBox = new TextBox();
    textBox.EnableViewState = false;
    textBox.Text = Text;
    textBox.TextChanged += new EventHandler(OnTextChanged);
    Controls.Add(textBox);
}
 
public event EventHandler TextChanged;
 
protected virtual void OnTextChanged(object sender, EventArgs e)
{
    if (TextChanged != null)
    {
        TextChanged(this, e);
    }
}

查看下测试效果:

你可能会更喜欢使用 HtmlTextWriter 完全控制 HTML 的呈现。但是,如果你想处理回传、事件以及创建复杂控件(如 GridView,或者导航助手),那么使用组合控件能极大化的简化工作。

为 TitledTextBox 提供更好的设计时支持

对于这个示例还有一个值得添加的细节。如果在 CreateChildControls()方法已经被调用来呈现控件之后修改了 Title 或者 Text 属性,一定需要确保子控件被重新生成。

比如在按钮回传的事件中修改了这 2 个属性后,回传结束,页面呈现时,仍能看见旧的属性值。这是因为 CreateChildControls()方法优先于按钮事件执行,因此控件属性的值还是比较旧的 ViewState 中保存的值。此时按钮事件执行,对控件的 ViewState 赋予了新的值,因此这种变化需要再次回传后才能发生。这并不是我们期待的效果和反应!

一定要有一种机制确保页面呈现后,用户修改了控件属性时,重新创建子控件并更新所有的值。

下面这段代码可以示例出这种机制(以 Title 举例):

public string Title
{
    get { return (string)ViewState["Title"]; }
    set
    {
        ViewState["Title"] = value;
 
        // 赋值时,如果控件已创建,那么控件沿用了上一次视图状态的值
        // 因此需要重新创建子控件
        if (this.ChildControlsCreated)
        {
            this.RecreateChildControls();
        }
    }
}

派生控件

派生控件指从现存的控件类派生出一个更加专用的控件。你可以覆盖或增加你需要的功能,而不需要重新创建整个控件,你可以省去很多工作。不过,此方式并非总是可行的,因为某些控件在私有方法里编写了一些基础设施的关键代码,你无法覆盖

       有时,你可创建一个派生控件以便能用某些样式或格式化属性预先初始化一个现存的控件。例如,你可以创建一个用于在 OnInit()方法里设置样式的自定义控件 Calendar 或 GridView,这样,当添加这些控件时,该实例就已经是你所期望的样式格式化了。

为特定数据创建标签

       创建自定义控件的一个普遍原因:为某些特定类型的数据而微调控件。

例如,标准的 Label 是一个灵活通用的工具,可以用来呈现文本内容并插入任意的 HTML 。然而,有时更需要一种能照顾到某些编码方式的更高级的文本输出方式。

Xml 控件,它允许用一个 XSLT 样式表在页面里显示 XML 内容。然而,XML 控件并未给出不使用 XSLT 样式表先将其转换来显示任意的 XML 的方式。因此,加入你想复制 IE 的行为,该怎么做呢?

IE 显示了一个彩色字符编码的 XML 标签的树形结构。你可以用 XSLT 样式表实现这种方法。然而,另一个有趣的选择是专门为 XML 内容创建一个自定义的 Label 控件,而这个 Label 控件可以自动应用你所需的格式。

示例介绍

首先,如果你不采取任何步骤,而试着显示 XML 内容,所有的 XML 标签都会被识别为无效的 HTML 标签,因此不会被显示,结果只会显示一个杂乱无章的代表所有元素内容的文本块:

可以通过 Server.HtmlEncode() 方法来稍微改善,但仍差强人意!所有的空白都被折叠了,所有的换行都被忽略了,导致了一个不可读的长字符串:

自定义 XmlLabel 控件

自定义 XmlLabel 控件通过在 XML 的开始和结束标签上应用格式化而解决了这个问题。这个功能被封装到一个名为 ConvertXmlTextToHtmlText()的静态方法中。之所以被实现为静态方法而非实例方法,就是为了能从其他控件中调用它来格式化文本并展示

ConvertXmlTextToHtmlText()使用下面的正则表达式来查找字符串中所有 XML 标签:

<([^>]+)> // 匹配小于号与大于号,及中间一系列非大于号的字符,遇到大于号匹配查找立即结束。

注意

正则表达式使用的是所谓的贪婪匹配(greedy matching),这意味着总是尽可能多的进行匹配。因此这个简单的 <.+> 表达式不可用。它将匹配文档中第一个小于号和文档末尾的大于号之间的所有内容。换言之,结果将只有一个匹配,这个匹配将所有内嵌的匹配都混为一谈。

一旦找到了一个匹配,下一步就是用你想要的文本替换这个匹配文本。替换表达式如下:

&lt;<b>$1</b>&gt;

用 HTML 实体字符来替换掉小于号和大于号。中间的文本用加粗来格式化。$1 是一个反向引用,它引用搜索表达式中用括号括住的文本。

一旦标签显示为粗体,最后一步就是用 &nbsp; 字符实体替换字符串中空格,用 <br /> 替换所有换行。下面是完整的代码:

public class XmlLabel : Label
{
    public static string ConvertXmlTextToHtmlText(string inputText)
    {
        string startPattern = "<([^>]+)>";
        Regex regEx = new Regex(startPattern);
        string outputText = regEx.Replace(inputText, "&lt;<b>$1</b>&gt;");
 
        outputText = outputText.Replace(" ", "&nbsp;");
        outputText = outputText.Replace("\r\n", "<br />");
        
        return outputText;
    }
 
    protected override void RenderContents(HtmlTextWriter output)
    {
        string xmlText = ConvertXmlTextToHtmlText(Text);
        output.Write(xmlText);
    }
}

这里没有调用 RenderContents()的基本实现。这是因为 XmlLabel 控件的目标是替代标签文本的呈现逻辑,而非补充!

       在这个框架的基础上,可以做很多工作来完善它,包括彩色编码和自动缩进。

       也可以使用类似的技巧创建标签(Label),自动把邮件地址和 URL 转换为链接(以 <a> 标签包装),格式化多行文本成无序列表等。

自定义服务器控件(扩展现有 Web 控件)相关推荐

  1. [转]利用ASP.NET 2.0创建自定义Web控件(1)

    原址:http://hi.baidu.com/sjbh/blog/item/cc58fd1bd35d3ad2ad6e7593.html   简介 从使用基本的文本编辑器到创作标记页面,Web 开发已经 ...

  2. 如何编写自定义的Web控件

    建一个自定义的Web控件MyContro的步骤: 1)引用 using System; using System.IO; using System.Drawing; using System.Web. ...

  3. Web控件和HTML控件

    ASP.NET中介绍了两种控件,一是,HTML控件:二是,Web控件.web控件是基于HTML控件加上runat="server"的属性.比HTML控件实现的功能更容易.HTML控 ...

  4. 【Asp.net】——Web控件与HTML控件的区别

    在看Asp.net视频的过程中,遇到对控件的一些解释,通过查询资料,简单的说说这二者的区别. 控件位置 在VS中,HTML控件位置在: Web控件位置: 控件样式 HTML控件: 除了几个特殊的控件: ...

  5. [原]动态创建Web控件制做计算器

    最近参加了Web基础开发的培训,收获不少,做了一个练习,在后台动态创建控件制作了一个简单功能的计算器.程序中控件创建好以后,往往不能放在想要的位置,前台的布局非常麻烦,我用Table.TableRow ...

  6. 用ASP.NET AJAX框架扩展HTML Map控件

    [摘要]在本文中,我将向你展示如何使用ASP.NET AJAX框架对添加可点击的热点的HTML Map控件进行扩展.经扩展后,当我们的鼠标移动到这些热点上后,即弹出关于这些热点的详细信息;但是,这些详 ...

  7. 免费打工仔:一个完善的ActiveX Web控件教程

    免费打工仔:一个完善的ActiveX Web控件教程 出自Ogre3D开放资源地带 跳转到: 导航, 搜索 原作者 David Marcionek. 翻译 免费打工仔 这个教程可以帮助你快速开发一个A ...

  8. 一个完善的ActiveX Web控件教程

    免费打工仔:一个完善的ActiveX Web控件教程 出自Ogre3D开放资源地带 跳转到:  导航,  搜索 原作者 David Marcionek. 翻译 免费打工仔 这个教程可以帮助你快速开发一 ...

  9. 探讨ASP.NET2.0中的Web控件改进技术

    全面探讨ASP.NET 2.0中的Web控件改进技术之概述(一) ASP.NET 2.0并没有抛弃1.1版本中的任何现有控件,而是增加了一组新的控件;同时还引入了若干新的控件开发技术.本系列文章将对这 ...

最新文章

  1. pku1384---Piggy-Bank(动态规划)
  2. WinRAR从入门到高级的操作技巧集合
  3. 复旦大学吴立德《数值优化》、《深度学习》和
  4. AUTOSAR从入门到精通100讲(三十九)-AUTOSAR 通信服务-Com模块两部曲-概念详解
  5. linux网络编程——客户端编程
  6. 苹果App Store曝出Bug 你遇到了么?
  7. iView UI常用组件DatePicker清空技巧
  8. 拷贝data/data/包名/files文件记下所有文件及文件夹到本地sdcard根目录teddyData_files文件夹下...
  9. 人民币对PHP金汇率,PHP货币是哪个国家的,和人民币的汇率怎么样,3万人民币能兑换多少?...
  10. Tarjan的缩点割点概述
  11. Python人工智能学习路线(长篇干货)
  12. 【游戏开发】小白学Lua(上)
  13. HIGEN海坚驱动器维修FDA7045伺服变频器维修
  14. php 获取微博cookie,c#获取新浪微博登录cookie
  15. 自由职业接单,大平台,有保障
  16. 有什么压缩图片的方法?这里有两个方法分享
  17. 【Python入门】Turtle海龟库:利用海龟画笔绘制花朵
  18. ORM一键还原系统官方版
  19. C++使用sscanf方便地读取数据
  20. 什么叫Research?Welcome to the real world

热门文章

  1. VTK:可视化之Camera
  2. OpenCV PCA提取对象的方向的实例(附完整代码)
  3. Qt Creator使用Clang工具
  4. C++实现cut rod切杆算法(附完整源码)
  5. C++构造函数的分类及调用
  6. 6.prometheus数据上报方式-pushgateway
  7. Jetty在win10上的配置,IDEA中配置Jetty,Maven中配置Jetty插件,Eclipse中配置Jetty插件及其使用,通过java代码内嵌Jetty Server
  8. ibatis中多表联接查询
  9. 02_3中方式的反射,通过Class.forName获得Class对象,通过类.class获得字节码对象,通过类实例.getClass()的方式获得Class对象
  10. Quartz + spring 定时任务常见错误总结