用户控件与自定义控件的概述

ASP.NET 支持语音列

用户控件与自定义控件的概述

为了根据您的需求自定义此列,我们希望邀请您提交您有关您感兴趣的主题以及您希望在将来的知识库文章和支持语音专栏中解决的问题的想法。您可以使用"意见"窗体提交您的想法和反馈。此列底部还有一个指向窗体的链接。

简介

你好!这是Parag,我是一名支持工程师,在微软ASP.NET支持小组工作一年多了。在加入 Microsoft 之前,我使用 Microsoft 技术从事基于 Web 的项目和桌面应用程序。在为客户提供质量支持的同时,我还看到过自定义控件存在一些混乱的情况,我只想花些时间解释有关自定义控件的一些概念。虽然看起来很糟糕,相信我,一旦你抓住它,你就会更好地欣赏ASP.NET。

概述

在本月的专栏中,我将讨论以下主题:

  • 什么是用户控件?

  • 什么是自定义控件?

  • 用户控件和自定义控件之间的基本区别是什么?

我还将介绍一些与自定义控件有关的高级主题,例如状态管理和自定义控件的呈现。

什么是用户控件?

用户控件是自定义的、可重用的控件,它们使用与 HTML 和 Web 服务器控件相同的技术。它们提供了一种跨 Web 应用程序ASP.NET分区和重用通用用户界面的简单方法。它们使用 Web 窗体页在其中工作的相同 Web 窗体编程模型。有关 Web 窗体编程模型的详细信息,请访问以下 Microsoft 开发人员网络 (MSDN) 网站:

Web 窗体页面简介 Web 窗体代码模型

如何创建用户控件

用于创建用户控件的语法与用于创建 Web 窗体页 (.aspx) 的语法类似。唯一的区别是,由于 Web 窗体页承载用户控件,因此用户控件不包括 <html><body> 和 <form> 元素。要创建用户控件,请按照以下步骤操作:

  1. 打开文本或 HTML 编辑器,并创建服务器端代码块,公开所有属性、方法和事件。

    <script language="C#" runat="server">
       public void button1_Click(object sender, EventArgs e)
       {
          label1.Text = "Hello World!!!";
       }
    </script>
    
  2. 为用户控件创建用户界面。

    <asp:Label id="label1" runat="server"/>
     <br><br>
    <asp:button id="button1" text="Hit" OnClick="button1_Click" runat="server" />
    

如何在 Web 窗体页中使用用户控件

  1. 在 Microsoft Visual Studio .NET 2002、Microsoft Visual Studio .NET 2003、Microsoft Visual Studio 2005 或任何文本编辑器中创建新的 Web 窗体页 (.aspx)。

  2. 声明# 寄存器指令。例如,使用以下代码。

    <%@ Register TagPrefix="UC" TagName="TestControl" Src="test.ascx" %>

    备注假设用户控件和 Web 窗体页位于同一位置。

  3. 要在 Web 窗体页中使用用户控件,请在@ Register指令之后使用以下代码。

    <html>
        <body>
              <form runat="server">
                   <UC:TestControl id="Test1" runat="server"/>
              </form>
        </body>  
    </html>
    

如何在 Web 窗体页文件后面的代码中以编程方式创建用户控件的实例

前面的示例使用@ Register指令在 Web 窗体页中声明性地实例化了用户控件。但是,您可以动态实例化用户控件并将其添加到页面。以下是执行此操作的步骤:

  1. 在可视化工作室中创建新的 Web 窗体页。

  2. 导航到为此 Web 窗体页生成的文件后面的代码。

  3. 在Page类Page_Load事件中,编写以下代码。

    // Load the control by calling LoadControl on the page class.
    Control c1 = LoadControl("test.ascx");
                
    // Add the loaded control in the page controls collection.
    Page.Controls.Add(c1);
    

    备注您可以在页面生命周期的某些事件中动态添加用户控件。 有关详细信息,请访问以下网站:

    控件以编程方式添加到 Web 窗体页,由 Scott Mitchell 以编程方式控制执行生命周期动态 Web 控件、回退和查看状态

如何处理用户控件

当请求具有用户控件的页面时,将发生以下情况:

  • 页面解析器解析在 @ 寄存器指令中的Src属性中指定的 .ascx 文件,并生成派生自System.Web.UI.UserControl类的类。

  • 然后,解析器将类动态编译到程序集中。

  • 如果您使用的是 Visual Studio,则仅在设计时,Visual Studio 会为用户控件创建文件后面的代码,并且该文件由设计器本身预编译。

  • 最后,通过动态代码生成和编译过程生成的用户控件类包括文件 (.ascx.cs) 后面的代码以及 .ascx 文件中编写的代码。

什么是自定义控件?

自定义控件是在服务器上执行、公开对象模型和呈现标记文本(如 HTML 或 XML)的编译代码组件,就像正常的 Web 窗体或用户控件一样。

如何为自定义控件选择基类

要编写自定义控件,应直接或间接地从System.Web.UI.CONTROL类或System.Web.UI.WebControl.WebControl 类派生新类:

  • 如果希望控件呈现非可视元素,则应从System.Web.UI.UI.control派生。例如,<meta> <head> 是非可视化渲染的示例。

  • 如果希望控件呈现在客户端计算机上生成可视界面的 HTML,则应从System.Web.UI.WEBControls.WebControl.WebControl 派生。

如果要更改现有控件(如按钮或标签)的功能,可以直接派生具有这些现有类的新类,并可以更改其默认行为。 简而言之,Control类提供了基本功能,通过该功能可以将其放在Page类的控件树中。WebControl类将功能添加到基本Control类中,用于在客户端计算机上显示可视内容。例如,可以使用WebControl类通过字体、颜色和高度等属性来控制外观和样式。

如何使用 Visual Studio 创建和使用从 System.Web.UI.CONTROL 扩展的简单自定义控件

  1. 启动视觉工作室。

  2. 创建类库项目,并为其命名,例如,自定义服务器控制Lib。

  3. 向项目添加源文件,例如,SimpleServerControl.cs。

  4. 在引用部分中包括System.Web命名空间的引用。

  5. 检查以下命名空间是否包含在SimpleServerControl.cs文件中。

    System
    System.Collections
    System.ComponentModel
    System.Data
    System.Web
    System.Web.SessionState
    System.Web.UI
    System.Web.UI.WebControls
    
  6. 使用控件基类继承SimpleServerControls类。

    public class SimpleServerControl : Control
  7. 覆盖Render方法以将输出写入输出流。

    protected override void Render(HtmlTextWriter writer) 
    {
     writer.Write("Hello World from custom control");
    }
    

    备注HtmlTextWriter类具有将 HTML 写入文本流的功能。HtmlTextWriter类的"写入"方法将指定的文本输出到 HTTP 响应流,并且与响应.Write方法相同。

  8. 编译类库项目。它将生成 DLL 输出。

  9. 打开现有应用程序或创建新ASP.NET Web 应用程序项目。

  10. 添加可以使用自定义控件的 Web 窗体页。

  11. 在ASP.NET项目的参考部分中添加对类库的引用。

  12. 在 Web 窗体页上注册自定义控件。

    <%@ Register TagPrefix="CC " Namespace=" CustomServerControlsLib " Assembly="CustomServerControlsLib " %>
  13. 要实例化或使用 Web 窗体页上的自定义控件,请添加 <form> 标记中的以下代码行。

    <form id="Form1" method="post" runat="server">
        <CC:SimpleServerControl id="ctlSimpleControl" runat="server">
        </CC:SimpleServerControl >
    </form>
    

    备注在此代码中,SimpleServerControl是类库中的控件类名称。

  14. 运行 Web 窗体页,您将看到来自自定义控件的输出。

如果不使用 Visual Studio,则需要执行以下步骤:

  1. 打开任何文本编辑器。

  2. 创建名为 SimpleServerControl.cs 的文件,并编写步骤 1 到 14 中给出的代码。

  3. 在 PATH 变量中,添加以下路径:

    c:\windows (winnt)\Microsoft.Net\Framework\v1.1.4322

  4. 启动命令提示符,然后转到存在SimpleServerControl.cs的位置。

  5. 运行以下命令:

    csc /t:库 /出:自定义服务器控制Lib。简单服务器控制.dll /r:系统.dll /r:系统.Web.dll SimpleServerControl.cs有关 C# 编译器 (csc.exe) 的详细信息,请访问以下 MSDN 网站:

    Visual Studio 2003 退休技术文档

  6. 要在 Web 窗体页上运行自定义控件,应执行以下操作:

    1. 在 wwwroot 文件夹下创建一个目录。

    2. 启动微软互联网信息服务(IIS)管理器,并将新目录标记为虚拟根目录。

    3. 在新目录下创建 Bin 文件夹。

    4. 将自定义控件 DLL 复制到 Bin 文件夹中。

    5. 将在前面的步骤中创建的示例 Web 窗体页放在新目录中。

    6. 从 IIS 管理器运行示例页面。

现在,您已经构建了一个简单的自定义控件,让我们来看看如何公开属性并在该自定义控件上应用设计时属性。

如何公开自定义控件上的属性

我将基于前面的示例构建,并介绍一个或多个属性,这些属性可以在 Web 窗体页上使用自定义控件时进行配置。 下面的示例演示如何定义一个属性,该属性将在控件中显示消息一定次数,如控件的属性中指定的那样:

  1. 在文本编辑器中打开SimpleServerControl.cs。

  2. 在"简单服务器控制"类中添加属性。

    public class SimpleServerControl : Control
    {
       private int noOfTimes;
       public int NoOfTimes
       {
           get { return this.noOfTimes; }
           set { this.noOfTimes = value; }
       } 
       protected override void Render (HtmlTextWriter writer)
       {
         for (int i=0; i< NoOfTimes; i++)
         {
           write.Write("Hello World.."+"<BR>");
         } 
       }
    }
    
  3. 编译自定义控件。

  4. 要在 Web 窗体页上使用自定义控件,将新属性添加到控件声明。

    <CC:SimpleServerControl id="ctlSimpleControl" NoOfTimes="5" runat="server"></CC:SimpleServerControl>
  5. 运行该页将显示自定义控件中的消息"Hello world",就像控件的属性中指定的多次一样。

如何在自定义控件上应用设计时属性

为什么需要设计时属性

在前面的示例中构建的自定义控件按预期方式工作。但是,如果要在 Visual Studio 中使用该控件,您可能希望在设计时选择自定义控件时,在"属性"窗口中自动突出显示NoofTimes属性。 要做到这一点,您需要向 Visual Studio 提供元数据信息,您可以使用 Visual Studio 中称为属性的功能来执行此操作。属性可以定义类、方法、属性或字段。当 Visual Studio 加载自定义控件的类时,它会检查在类、方法、属性或字段级别定义的任何属性,并在设计时相应地更改自定义控件的行为。 要查找有关属性的详细信息,请访问以下 MSDN 网站:

Visual Studio 2003 退休技术文档让我们构建一个使用常用属性的示例:

  1. 在文本编辑器中打开SimpleServerControl.cs。

  2. 在类级别引入一些基本属性,例如,默认属性、工具箱数据和标记前缀 Attrbute。我们将基于这三个属性构建示例。

            [
    // Specify the default property for the control.
    DefaultProperty("DefaultProperty"),
    
    // Specify the tag that is written to the aspx page when the
            // control is dragged from the Toolbox to the Design view. 
    // However this tag is optional since the designer automatically 
    // generates the default tag if it is not specified.
    ToolboxData("<{0}:ControlWithAttributes runat=\"server\">" +
    "</{0}:ControlWithAttributes>")
    ]
    public class ControlWithAttributes : Control
    {
    private string _defaultProperty;
    public string DefaultProperty
    {
    get { return "This is a default property value"; }
    set { this._defaultProperty = value; }
    }
    
    protected override void Render(HtmlTextWriter writer)
    {
    writer.Write("Default Property --> <B>" + 
    DefaultProperty + "</B>");
    }
             }
    
  3. 还有一个称为"标记前缀Attrbute"的标记。它是一个程序集级属性,在将控件从工具箱拖动到设计器时为标记提供前缀。否则,设计器将默认生成前缀,如"cc1"。标记前缀attrbute不直接应用于控件类。要应用TagprefixAttrbute,请打开AssemblyInfo.cs,包括以下代码行,然后重建项目。

    [assembly:TagPrefix("ServerControlsLib ", "MyControl")]

    备注如果要使用命令行生成源,则需要创建AssemblyInfo.cs文件,将文件放在包含所有源文件的目录中,并运行以下命令来生成控件:

    > csc /t:库 /出:服务器控制Lib.dll /r:系统.dll /r :系统.Web.dll *.cs

用户控件和自定义控件之间的基本区别是什么?

现在,您已经了解了什么是用户控件和自定义控件以及如何创建它们,现在让我们快速了解一下它们之间的差异。

因素

用户控制

自定义控件

部署

专为单应用程序方案而设计 在源代码 (.ascx) 中与应用程序的源代码一起部署 如果需要在多个应用程序中使用相同的控件,则会带来冗余和维护问题

设计使其可用于多个应用程序 在应用程序的 Bin 目录或全局程序集缓存中部署 易于分发,且无冗余和维护问题

创造

创建类似于 Web 窗体页的创建方式;非常适合快速应用开发 (RAD)

编写涉及大量代码,因为没有设计器支持

内容

当您需要在固定布局中提供静态内容时(例如,在创建页眉和页脚时)时,这是一个更好的选择

更适合于应用程序需要显示动态内容时;可跨应用程序重复使用,例如,对于具有动态行的数据绑定表控件

设计

编写不需要太多的应用程序设计,因为它们是在设计时创作的,并且大多包含静态数据

从头开始编写需要很好地了解控件的生命周期和事件执行的顺序,这在用户控件中通常要处理

高级主题

接下来,让我们看一下在开发自定义控件时可以使用的一些高级功能。

状态管理

Web 应用程序基于 HTTP 构建,它是无状态的。在每个请求上创建页面及其子控件,并在请求结束后释放。要在经典 ASP 编程中保持状态,请使用会话和应用程序对象。但是,为此,您需要执行大量编码。为了避免这种情况,ASP.NET提供了一种称为视图状态的机制,用于在多个请求中维护状态。要了解有关状态管理和查看状态的信息,请访问以下 MSDN 网站:

Web 窗体状态管理简介 ASP.NET视图状态 使用视图状态保存 Web 窗体页面值

在自定义控件中使用视图状态的示例

ViewStateExample.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;

namespace ServerControlLib
{
/// <summary>
/// When a page framework reloads this control after postback, it   
        /// will restore the values which are in view state.
/// This control can easily perform state management without 
        /// implementing our own logic for maintaining the state.
/// </summary>
public class ViewStateExample : WebControl
{
// Text to be displayed in Text box control.
private string _text;

/*
 * This property needs to be populated before every 
                 * postback in order to 
 * retain its value.
*/ 
public string Text
{
get { return (_text == null) ? "_text property is empty"  : _text; }
set { _text = value; }
}

/*
 * This property needs to be filled once and should be 
                 * available on the successive postbacks.
*/ 
public string TextInViewState
{
get
{
object o = ViewState["TextInViewState"];
return (o == null) ? "View state is empty" : (string)o;
}
set { ViewState["TextInViewState"] = value; } 
}

/*
 * Over-ridden method on WebControl base class which                   
                 * displays both of the property values 
 * i.e. one stored in view state and other which is not 
                 * saved in view state.
*/
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("Text Without View State = ");
writer.Write(Text);
writer.Write("<hr><br>");
writer.Write("Text In View State = ");
writer.Write(TextInViewState);
}
}
}
在 Web 窗体页上使用上一个控件的示例

ViewStateExampleDemo.aspx

<%@ Page Language="C#" %>
<%@ Register TagPrefix="CC" Namespace="ServerControlLib" Assembly = "ServerControlLib" %>

<html>
  <head>
    <script runat="server">
      void button1_Click(object sender, EventArgs e)
      {
          Control1.Text = textbox1.Text;
          Control1.TextInViewState = textbox2.Text;
      }
    </script>
  </head>
  <body>
    <form runat="server" ID="Form1">
      <br>
      Property Value Without View State: <asp:TextBox id="textbox1" 
        runat="server" />
      <br>
      Property Value with View State: <asp:TextBox id="textbox2" 
        runat="server" />

      <asp:Button text="Cause Postback" onClick="button1_Click" 
        id="button1" Runat="server" />

      Output from the ViewStateExample Control :
      <CC:ViewStateExample id="Control1" runat="server"/>
    </form>
  </body>
</html>

渲染

在本节中,我将简要描述从Control类或WebControl类派生自定义控件时应重写哪些方法。

System.Web.UI.Control 类的呈现方法

有关System.Web.UI.Control类的呈现方法的信息,请访问以下 MSDN 网站:

控件.渲染方法 控制.渲染控制方法 控制.渲染儿童方法

如何在页面上呈现控件

每个页面都有一个控件树,表示该页的所有子控件的集合。要呈现控件树,将创建HtmlTextWriter类的对象,其中包含要在客户端计算机上呈现的 HTML。该对象将传递到RenderControl方法。反过来,RenderControl方法调用"渲染控制"方法。然后,Render方法在每个子控件上调用RenderChild方法,创建递归循环,直到达到集合的末尾。此过程最好通过以下示例代码进行说明。

public void RenderControl(HtmlTextWriter writer) 
{
    // Render method on that control will only be called if its visible property is true.
    if (Visible)
    {
        Render(writer);
    }
}

protected virtual void Render(HtmlTextWriter writer) 
{
    RenderChildren(writer);
}
protected virtual void RenderChildren(HtmlTextWriter writer) 
{
    foreach (Control c in Controls) 
    {
        c.RenderControl(writer);
    }
} 
系统.Web.UI.WebControl 类的呈现方法

有关System.Web.UI.WebControl类的呈现方法的信息,请访问以下 MSDN 网站:

WebControl.renderbegin标记方法 WebControl.渲染内容方法 WebControl.renderendTag方法

WebControl 类的呈现方式

以下代码示例显示了自定义控件的Render方法。

protected override void Render(HtmlTextWriter writer)
{
    RenderBeginTag(writer);
    RenderContents(writer);
    RenderEndTag(writer);
}

您无需重写WebControl类的"渲染"方法。如果要在WebControl类中呈现内容,则需要重写"RenderContents"方法。但是,如果仍要重写"渲染"方法,则必须按前面的代码示例中显示的特定顺序重写RenderBeginTag方法以及RenderEndTag方法。

结论

现在,ASP.NET 1.0 和 ASP.NET 1.1 中的用户控件和自定义控件就全部了。我希望本专栏帮助您了解它们之间的基本区别以及开发它们可以采取的各种方法。 谢谢你的时间。我们期望在不久的将来编写更多有关自定义控件的高级主题,如状态管理、控件样式、复合控件和自定义控件的设计时支持。 有关控件的详细信息,请访问以下 MSDN 网站:

ASP.NET服务器控制开发基础知识 广泛检查用户控件 构建模板化自定义ASP.NET服务器控件ASP.NET 服务器控件中的事件 复合控件与用户控制 开发ASP.NET服务器控件 开发自定义控件:关键概念 添加设计时支持ASP.NET控件

与往常一样,请随时使用"窗体提交有关您希望在将来专栏或知识库中讨论的主题的想法。

需要更多帮助?

扩展你的技能
了解培训
抢先获得新功能
加入 Microsoft 内部人员

此信息是否有帮助?

谢谢您的反馈意见!

谢谢你的反馈! 可能需要转接到 Office 支持专员。

×