运行时复制 WebControls 以提高 Web 可用性
一个自定义控件,用于在 ASP.NET Web 窗体的顶部和底部镜像常用按钮。
引言
Web 应用程序用户面临着一个不幸的现实:网页会滚动。虽然这对于查看文档“有用”,但当您被迫向下滚动以保存对表单的更改时,可能会很烦人。当您的工作涉及每天这样做大约 1,000 次时,真的“非常”烦人。敏锐地,我的客户注意到了这一点,并要求我将保存、取消、帮助等按钮放在每个页面的顶部和底部。
显然,您无需费力即可做到这一点。只需复制页面顶部的控件,为其提供新的 ID
,然后引用其他控件正在使用的相同事件处理程序。
但我们是程序员,对吧?并且,从基因上讲,我们“厌恶”重复代码。谁真的想调用他们的控件 btnSave1
和 btnSave2
?完全不酷。
一定有“更好的方法”。
更好的方法
如果您有一种方法可以简单地复制一组控件,使其在同一页面上出现多次怎么办?并且在运行时完全执行复制,而不是在设计时执行?
输入... Mirror
控件。 Mirror
控件是一个非常简单的自定义控件,其唯一功能是重新呈现另一个控件,使其在页面上的多个位置出现。
事实证明,.NET 控件呈现模型可用于多次生成控件的 HTML。任何 WebControl
,包括自定义控件,都将具有一个 RenderControl()
方法,Page
使用该方法来生成控件的 HTML。您也可以使用它...
使用 Mirror 控件
与其他 WebControl
一样,使用 Mirror
控件非常复杂。 它是这样工作的:
<cc1:Mirror id="Mirror1" ControlID="ButtonPanel1" runat="server" />
- 为您的控件指定一个
ID
,例如Mirror1
。 如果你不这样做,虽然不是绝对必要,但 Visual Studio 会为你创建一个。 - 通过
ControlID
属性指定要镜像的 WebControl 的ID
。 - 是的,就是这样。
在页面的顶部,请务必引用您的自定义控件程序集,如下所示;
<%@ Register TagPrefix="cc1" Namespace="MirrorControl"
Assembly="MirrorControl" %>
工作原理
非常简单,Mirror
控件的 Render()
函数;
- 使用
Page.FindControl()
方法定位您在ControlID
属性中标识的控件。 - 通过调用其
RenderControl()
方法,强制标识的控件自行呈现。
实际的智能只是一些代码行。这是 Mirror
控件的“整个”类定义。 谁说自定义控件必须很复杂?
/// <summary>
/// Mirror control.
/// Duplicates the rendered HTML of another control on the page.
/// </summary>
[ToolboxData("<{0}:Mirror runat=server></{0}:Mirror>")]
public class Mirror : WebControl
{
// This will be automatically populated on each Page_Load
// with the value of the Mirror control's ControlID attribute.
public string ControlID = null;
protected override void Render (HtmlTextWriter writer)
{
// Ensure that the ControlID was defined
// otherwise abort the render
if (ControlID == null)
return;
// Locate the control identified by ControlID
Control c = Parent.FindControl (ControlID);
// If the specified control was not found, abort
if (c == null)
return;
// Call the control's Render function in order to
// generate the Mirror control's HTML.
// This, in a nutshell is the mirroring process.
c.RenderControl (writer);
}
}
警告和限制
- 您指定的控件将被“精确地”复制,就像在其他地方呈现一样。再次强调,“精确地”。这包括诸如
ID
属性之类的内容。 如果您有引用这些ID
属性的 JavaScript,您可能会遇到问题。 - 避免镜像数据输入控件(例如
TextBox
、ListBox
、CheckBox
、DropDownList
等),因为页面上只有最顶端的控件才能正常工作。在回发期间,ASP.NET 回发处理程序只会关注第一个匹配ID
的控件,并从那里加载其值。 因此,如果您更改页面上较低位置的控件实例的内容,则其值将在回发时丢失。 - 如果您在布局中使用绝对定位,请确保不要在镜像控件上使用它们。 否则,两组控件都将在同一位置呈现,一个位于另一个之上。[特别感谢 UnderWing 指出这一点]
提示与技巧
Mirror
控件旨在仅复制一个WebControl
。 如果您希望复制一组控件,您可以使用多个Mirror
控件,或者,如果它们是相邻的,只需将您的控件包装在Panel
中,然后引用Panel
的ID
即可。- 如果您认为有用,您可以在同一页面上多次镜像相同的控件。
- 避免镜像数据输入控件(例如
TextBox
、ListBox
、CheckBox
、DropDownList
等),如上所述。 - 避免镜像控件的绝对定位。
- 如果您需要访问控件的两个实例,
FindControl()
函数只会定位其中一个。 但是,您可以迭代Page.Controls
集合并定位两个实例。