自定义网页控件的所见即所得

分享于 

9分钟阅读

Web开发

  繁體

Sample Image - ConvertUserToCustom.jpg

介绍

本文描述了一种控制工程技术,使开发人员可以使用 Visual Studio IDE的标准工具来设计自定义控件。

背景

复杂项目构建阶段所做的决策并不总是明确的。 为了证明概念,满足期限或者实施标准,做出了妥协。 随着时间的推移,这些损害开始积累到重要的"设计债务"中,当离开无人参与时,会引起。 对于保持设计债和产生的系统熵来说,重构与测试驱动开发可能是最可靠的方法。

专门使用 ASP.NET 网络项目,经常会看到尝试使用预先存在站点的类库,将标记复制到新项目中,并稍微修改指令背后的代码。 因这里,一个专门为一个项目构建的'内部'用户控件可能会成为多个新的前端所必需的部分。 但是,由于它们本身的限制远远超过了动态和定制控件,用户控件本身就是一个可以重用的,并且是可以重用。 如果将粗糙的用户控件转化为它的平滑且容易部署'自定义'变量的简单步骤,则会有什么问题。 本文将说明一种适合将用户控件转换为自定义控件的方法,同时保留原始的工作和功能。 但是作者完全理解,在从头开发新的复合控件控件时,这种方法的显著积极效果也可以实现。 前面两段简单地提供了读者的历史 background,以及这个创造性carping练习的一个借口。

更多用户控件 vs 自定义控件

"用户"控件( 在概念中) ) are比"自定义"控件更容易使用,因为 Visual Studio的设计时间能力使得UI构建过程变得简单快捷。 不需要手动控制代码的位置和行为,就像自定义控件一样。 如果要求用户界面的简单可以重用元素不会继承并仅向它的所在的项目公开,则选择。

但是,尝试将用户控件放到它的下一级抽象或者部署到托管项目的外部是非常可以行的。 这是自定义控件开始验证它的价值的地方。 它们可以被有效继承,并且具有轻量级的部署空间/开销。 现在,是否可以将用户控件的被视图设计功能与自定义控件和shamelessly合并在一起。 在本文中,我们将尝试这样做。

示例解决方案

我已经包括了控制项目 ( ControlTestRange 类库) 和项目( ControlTester - web项目),用于测试样例代码中的控件。 都是用 Visual Studio 2005构建的。 解决方案文件为 solutionProjectsControlTestRangeControlTestRange.sln。

我还没有尝试 VS2003/.NET 1.1. 但有理由相信它也会工作得很好。

步骤 1 - 设计用户界面

我们将从设计示例控件的UI开始。 这个想法是尽可以能简单和无用的,防止人们试图将它们插入真实的生活项目。 毕竟,这只是对技术的一个说明。 而不是一个开源产品。 首先,我向控件项目添加一个新的HTML页面,并用简短但非常有意义的表示法替换了模板生成的整个 HTML:

然后,我将tcp文件重命名为" controlMarkup.ascx",希望IDE能够使它具有与'正常'用户控件( 当它出现时我非常震惊) 相同的设计时间。 以下是HTML和设计演示中的结果:

Control mark-up

这个'幻像'ascx模板上有两个控件- 一个是服务器端的List,另一个是基本的HTML按钮。 按钮提供了更基本的事件处理程序。

步骤 2 - 添加控件类

我的名字不太好,所以我的测试控件是uncomplicatedly足够的TestControl。 我将它添加到控制项目中,并使它从 Control 类派生。 也可以从 CompositeControl 类派生,因为它( 在典型的精确和简洁的msdn语言中)"实现包含子控件的Web控件所需的基本功能。

步骤 3 - 嵌入式资源

为了简化服务器控件部署,我们对部署单元的最小可能数量感兴趣。 理想情况下,应该只存在一个- 一个承载我们世界最大控制库的程序集。 添加标记文件作为嵌入资源,我们的项目很好地解决了这个任务。 控件项目中," controlMarkup.ascx"文件上的生成操作属性设置为"嵌入式资源"。

Embedded Resource

若要检索这里资源,我创建了一个简短的helper 方法 GetResource:

privatestring GetResource(string resourceName)
{
 Stream stream = 
 Assembly.GetExecutingAssembly().GetManifestResourceStream(
 GetType(), resourceName);
 using (StreamReader reader = new StreamReader(stream))
 {
 return reader.ReadToEnd();
 }
}

它被用来获取 controlMarkup.ascx的内容:

string content = GetResource("controlMarkup.ascx");

你可以在MSDN上找到关于嵌入式资源的更多信息。 这个功能非常有趣,特别是由于 ASP.NET 2.0不是完全了解这种功能,并且亲切地提供了一个新的。令人兴奋的。

步骤 4 - 连接控件

我们早发现了从程序集的黑暗深度中挖掘嵌入资源是多么容易。 现在,将这些知识放在一起,我们将重写基类的OnLoad 方法。

protectedoverridevoid OnLoad(EventArgs e)
{
 base.OnLoad(e);
 if (DesignMode) return;
 string content = GetResource("controlMarkup.ascx");
 Control control = Page.ParseControl(content);
 this.Controls.Add(control);
 m_Ddl = control.FindControl("ddlTrigger") as DropDownList;
 m_Ddl.SelectedIndexChanged += new EventHandler(ddl_SelectedIndexChanged);
}

从嵌入的加载到字符串变量后,宿主页面公开的魔术 ParseControl 方法将它的转换为一个 Control的实例。 是正式 Alive ! 下一步是将怪物添加到 TestControl 本身。 这个练习的一个重要部分是确保服务器控件在这个环境中是完全功能化的。 实例级别字段 m_Ddl 被指定给frankenstein集合( 我们知道这对事实起作用,因为我们实际上构建了怪物)的Controls 成员的一个引用。 然后将事件处理程序分配给列表事件的下拉 SelectedIndexChanged。 处理程序中的代码更改下拉 List的background 颜色,从而产生一些戏剧性的效果:

void ddl_SelectedIndexChanged(object sender, EventArgs e)
{
 m_Ddl.BackColor = 
 System.Drawing.Color.FromName(m_Ddl.SelectedValue);
}

运行解决方案时观察到异常的正常行为。 事件处理程序( client- ) 和服务器端都正确响应,控件的内部状态保留为( 下拉列表的background 颜色实际上改变了)。 不用说,客户端" onclick"处理程序也按顺序触发:

End result

步骤 5 - FFFFFF ( fat-free-food-for-farther -'') 和结论

在大多数情况下,在HTML和 C# 或者VB中编码控件的外观非常少。 这里演示的方法通常是基于 System.UI.Web.Page 类的ParseControl 方法的。 很自然,在宿主页面上注册的标记前缀可以被 ParseControl 识别。 这意味着如果有必要,可以将第三方控件添加到'n。frankenstein',如果页本身意识到它们的存在。

让读者了解这项技术的更高级方面: 视图视图管理,子类化或者在母版页中托管它,仅用于 NAME。 请随意分享你能发现的,并且像往常一样快乐的编码 !


相关文章