第5章 用户控件
用户控件是一种复合控件,可以将其他多种服务器控件组织起来。用户控件用于服务器端缺少所需要的控件的情况,它提供了一个简便的方法来实现代码的可重用性,简化了操作。开发人员创建了用户控件后,可以在同一应用程序的多个页面中重用该控件,使应用程序更加模块化。本章将给大家详细讲解用户控件的用法。
5.1 用户控件简介
知识点讲解:光盘\视频讲解\第5章\用户控件简介.wmv
用户控件类似于ASP.NET网页,是一种轻量级自定义用户界面的控件。开发人员可以向控件添加现有的Web服务器控件和标记,并且可以定义控件的属性和方法。在编写Web应用程序时,把可能重复出现的元素都用用户控件来实现,将大大减少代码维护的成本。本节我们来初步了解用户控件。
用户控件具有用户界面和代码后置文件,可以在页面上添加控件、响应事件代码等。但用户控件和ASP.NET页面还是有不同之处的,它们的具体区别如表5.1所示。
表5.1 用户控件与ASP.NET页面的区别
用户控件的@Control指令对配置及其他属性进行定义。用户控件必须被包含到ASP.NET页面中后,才可以被浏览器请求。用户控件的基类UserControl和ASP.NET页面的基类Page派生自同样的TemplateControl类,因此它们可以共享很多相同的方法和事件。用户控件的使用方法很简单,和Web控件一样,拖入页面并设置它的属性就可以了。
5.2 创建用户控件
知识点讲解:光盘\视频讲解\第5章\创建用户控件.wmv
在创建用户控件之前,需要先设计Web页面中能够重用的可见对象。Visual Studio 2012提供了创建用户控件的模板,其创建过程与创建ASP.NET页面的过程非常相似。下面我们来学习创建一个用户控件的具体步骤。
(1)创建用户控件的第一步是建立一个.ascx文件。在.ascx文件中,不能包含html、head、body和form这样的标签,因为包含.ascx的.aspx文件已经包含了这样元素。一个.ascx文件只能包含方法等和可能用户相关的内容。
(2)建立了.ascx文件后,要为用户控件增加一些可视的代码。在用户控件中可以包含所有的Web控件。
(3)在用户控件中定义属性和方法。
【示例5-1】下面创建一个用户控件。
(1)创建一个名称为“创建一个用户控件”的网站。
(2)在解决方案资源管理器中用鼠标右键单击网站,在弹出的快捷菜单中选择“添加新项”命令,在打开的“添加新项”对话框中选择“Web用户控件”模板,并将该控件命名为WebUserControl,如图5.1所示。
图5.1 “添加新项”对话框
(3)在创建好的WebUserControl.ascx文件中,添加一个日历控件Calendar。Visual Studio 2012生成的代码如下所示:
示例5-1:创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-1\创建一个用户控件\WebUserControl.ascx
在用户控件代码中,没有ASP.NET页面包含的<html>、<head>、<body>和<form>等标签。代码第一行是一个以@Control开头的声明,它的属性和Page非常相似;Language用于指定用户控件所使用的语言;AutoEventWireup用于判断是否自动执行事件,该事件是指特定页面生命周期阶段定义的程序;CodeFile是用户控件的代码后置文件;Inherits用于指定当前页面是从特定代码的后置类中继承的。该用户控件的代码后置文件中的代码如下所示:
示例5-1:创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-1\创建一个用户控件\WebUserControl.ascx.cs
用户控件是一个局部类,该类将合并由ASP.NET自动生成的一部分代码。在该用户控件中简单地放了一个日历控件,主要用于演示用户控件的开发流程。
(4)创建一个名称为“使用用户控件”的Web窗体。因为用户不能直接访问用户控件,所以需要将用户控件添加到页面上来以查看用户控件的运行效果。为了将控件放在ASP.NET页面上,首先要使用@Register指令注册用户控件,代码如下:
示例5-1:创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-1\创建一个用户控件\使用用户控件.aspx
在@Page指令下面,放了一个@Register指令,用来声明当前页面中使用的用户控件。在该指令中包含三个属性,具体含义如下所示。
- src:指定用户控件文件的位置。
- Tagname:指定与该类相关联的任意别名,在使用用户控件时会用到。
- Tagprefix:标记前缀,存放使用该用户控件时需要引用的命名空间。
(5)用户控件注册完成之后,就可以在Web页面中使用了。在“使用用户控件.aspx”窗体中使用指定的tagprefix和tagname来声明用户控件,代码如下:
示例5-1:创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-1\创建一个用户控件\使用用户控件.aspx.cs
运行结果如图5.2所示。
图5.2 运行结果图
在该示例中,我们创建了一个用户控件,将其在Web页面顶端注册后即可使用。为了能够在整个应用程序中使用注册的用户控件,可以在应用程序的Web.config配置文件中注册该用户控件,代码如下:
示例5-1:创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-1\创建一个用户控件\Web.config
注意:在Web.config文件中注册了用户控件后,就可以从解决方案资源管理器中把WebUserControl.ascx拖到Web设计视图上了。Visual Studio 2012会根据在Web.config中注册的tagname和tagprefix来声明用户控件。
5.3 将.aspx文件中内容转换为.ascx文件
知识点讲解:光盘\视频讲解\第5章\将.aspx文件中内容转换为.ascx文件.wmv
如果一些Web页面中的内容需要经常重用,此时可以将这些已有的.aspx文件中的内容转换为一个用户控件。在操作过程中需要注意以下内容:
- 移除所有的<html>、<head>、<form>和<body>标签。因为这些标签只能用于ASP.NET页面,不能用在用户控件中。<!DOCTYPRE>标签是文档类型定义,在一个ASP.NET页面中只能出现一次,因此也要移除。
- 将@Page指令替换为@Control指令,并且移除一些@Control指令不支持的属性(如CodePage、ResponseEncoding等)。
- 如果没有使用代码后置模型,确保仍然在@Control指令中使用ClassName属性包含一个类名。这样使得用户控件的页面能够支持强类型用户控件,允许访问添加到用户控件中的属性和方法。如果使用代码后置模型,则需要将代码后置类从Page类继承更改为从UserControl类继承。
- 将扩展名由.aspx修改为.ascx。
将以上操作完成后,一个用户控件就形成了。可以按照前面的方法,将用户控件添加到ASP.NET页面中使用。
【示例5-2】下面创建一个名称为“转换现有页面为用户控件”的网站,在该网站上添加一个名称为“转换现有页面为用户控件示例.aspx”的Web窗体,并在Web窗体上添加一个日历控件。代码如下所示:
示例5-2:转换现有页面为用户控件
源码路径:光盘\源文件\Chapter5\示例5-2\转换现有页面为用户控件\转换现有页面为用户控件示例.aspx
运行结果如图5.3所示。
图5.3 运行结果图
按照上文的规则,将Web页面转换为一个用户控件,代码如下所示:
5.4 编程处理用户控件
示例5-2的用户控件中共享了静态的Web页面元素,但却不能在ASP.NET页面中通过编程调整日期和响应事件,因此限制了用户控件的使用。在ASP.NET中,可以为用户控件添加属性、事件、方法以及一些客户端访问的功能。本节我们来学习如何通过编程处理用户控件。
5.4.1 公开用户控件中的属性
知识点讲解:光盘\视频讲解\第5章\公开用户控件中的属性.wmv
在前面的示例中,我们在用户控件中添加了日历控件。默认情况下,将用户控件添加到ASP.NET页面中后,页面与该日历控件实例之间是无法进行交互的。若要获得这种交互功能,就需要将用户控件中需要设置的属性公开,使其变成日历控件的属性。
【示例5-3】下面创建一个名称为“公开用户控件中的属性”的网站。在该网站上添加一个名称为“公开用户控件中的属性示例.aspx”的Web窗体,一个名为WebUserControl.ascx的用户控件,并在该用户控件中添加一个日历控件,具体代码如下所示:
示例5-3:公开用户控件中的属性
源码路径:光盘\源文件\Chapter5\示例5-3\公开用户控件中的属性\WebUserControl.ascx
然后在用户控件的后置代码文件中添加一些属性,实现允许ASP.NET页面与日历控件交互的功能。具体代码如下所示:
示例5-3:公开用户控件中的属性
源码路径:光盘\源文件\Chapter5\示例5-3\公开用户控件中的属性\WebUserControl.ascx.cs
当在用户控件中定义了public属性之后,就可以在使用了用户控件的ASP.NET页面中设置日历控件的属性了。其属性有三种设置方式:
- 选中用户控件,打开属性面板,设置属性,如图5.4所示。
图5.4 属性面板
- 直接在代码中设置属性,代码如下:
示例5-3:公开用户控件中的属性
源码路径:光盘\源文件\Chapter5\示例5-3\公开用户控件中的属性\公开用户控件中的属性示例.aspx
- 通过编程方式设置属性。
示例5-3:公开用户控件中的属性
源码路径:光盘\源文件\Chapter5\示例5-3\公开用户控件中的属性\公开用户控件中的属性示例.aspx.cs
当属性添加到用户控件中之后,页面初始化的顺序如图5.5所示。
图5.5 执行顺序
注意:如果在用户控件的Page_Load事件中进行初始化设置,可能会覆盖客户端指定的设置。因此不建议在用户控件的Page_Load事件中进行初始化设置。
5.4.2 用户控件事件
知识点讲解:光盘\视频讲解\第5章\用户控件事件.wmv
事件是用户控件和Web页面之间的另一个沟通方式。使用事件可以让Web页面代码来响应用户控件中的操作。带有用户自定义控件页面的事件主要有以下几种情况:
- 主页面里的Page_Load事件。
- 主页面里的Web控件产生的事件。
- 用户自定义控件里的Page_Load事件。
- 用户自定义控件里的Web控件产生的事件。
这四种事件的执行顺序是固定的,在程序开发中必须以此为规律。它们的具体执行顺序如图5.6所示。
图5.6 事件执行顺序
【示例5-4】下面演示为用户控件添加事件的情况。
(1)创建一个名称为“添加用户控件事件”的网站。
(2)创建一个用户控件,名称为WebUserControl.ascx。在该用户控件中添加三个标签控件、两个文本框控件和一个按钮控件,具体代码如下:
示例5-4:添加用户控件事件
源码路径:光盘\源文件\Chapter5\示例5-4\添加用户控件事件\WebUserControl.ascx
接下来编写用户控件的后置代码文件。首先定义一个委托和事件,然后定义按钮的单击事件。当用户控件中的按钮被单击时,引发该按钮的单击事件。具体代码如下:
示例5-4:添加用户控件事件
源码路径:光盘\源文件\Chapter5\示例5-4\添加用户控件事件\WebUserControl.ascx.cs
(3)创建一个Web窗体,名称为“添加用户控件事件示例.aspx”,在其中拖入用户控件。具体代码如下:
示例5-4:添加用户控件事件
源码路径:光盘\源文件\Chapter5\示例5-4\添加用户控件事件\添加用户控件事件示例.aspx
运行结果如图5.7所示。
图5.7 运行结果图
注意:必须将事件的订阅放在用户控件后置代码中。如图5.6所示,程序会先执行主页的控件事件,后执行用户的控件事件,因此,若将事件放在主页代码中,则执行用户控件事件时就会覆盖主页的设置。
5.5 动态创建用户控件
知识点讲解:光盘\视频讲解\第5章\动态创建用户控件.wmv
在项目开发中,有时需要在运行时,根据上下文的参数信息来动态创建用户控件。动态创建用户控件需要遵循三个规则:触发Page_Load事件时,创建并添加用户控件;使用容器控件或者PlaceHolder控件(该控件用作其他控件的容器)确保用户控件出现在正确的位置;设置用户控件的ID属性,给用户控件一个唯一的名字。
为了实现用户控件的动态创建,需要调用Page.LoadControl()方法。该方法接受.ascx的文件名称,并返回一个Control对象。
注意:PlaceHolder控件类似于面板控件,它在客户端什么也不生成。该控件的主要作用就是往里面添加子控件,只是表示控件树上的一个位置。
【示例5-5】下面创建一个名称为“动态创建用户控件”的网站。在该网站中使用示例5-1和示例5-4中的用户控件,分别命名为WebUserControl.ascx和MyUserControl.ascx,然后创建一个名称为Default.aspx的Web窗体,并在该窗体中添加一个列表框控件、一个按钮控件和一个PlaceHolder控件。具体代码如下:
示例5-5:动态创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-5\动态创建用户控件\Default.aspx
在DropDownList列表框控件的Value属性中,放的是WebUserControl.ascx和MyUserControl.ascx两个用户控件。当单击“动态创建用户控件”按钮时,在PlaceHolder控件中加载用户控件,具体代码如下:
示例5-5:动态创建用户控件
源码路径:光盘\源文件\Chapter5\示例5-5\动态创建用户控件\Default.aspx.cs
运行结果如图5.8和图5.9所示。
图5.8 运行结果图(1) | 图5.9 运行结果图(2) |
在该示例中,LoadUserControl()方法接收一个用户控件的路径名和一个PlaceHolder对象,然后调用LoadControl()方法加载指定位置的用户控件,为该用户控件对象指定唯一的ID,并将其加载到PlaceHolder控件集合中,当单击“动态创建用户控件”按钮时,调用LoadUserControl()方法,来加载用户选择的用户控件。
注意:在示例中,将当前用户控件的路径保存到Session变量中,然后在Page_Load事件中再加载用户控件。动态创建的用户控件进行页面回发时,会丢失用户控件的内容,因此需要在页面回发时重新创建,才能显示用户控件的内容。
5.6 小结
本章主要介绍了ASP.NET的用户控件,包括用户控件的创建方法、将已有页面转换成用户控件、编程处理用户控件和动态加载用户控件。重点是用户控件的创建方法和编程处理用户控件,难点是动态加载用户控件。有兴趣的读者可以自己尝试着运用这些方法在自己的网站中添加用户控件。
5.7 本章习题
习题5-1 在Visual Studio 2012中新建一个网站,命名为chapter5_1。在该网站上添加一个Web用户控件,命名为WebUserControl.ascx。在该用户控件中添加一个DropDownList列表框控件,并为其添加六个列表项:美国、日本、英国、法国、加拿大和澳大利亚。
【分析】本题目主要考查的是对创建用户控件的掌握情况。
注意:用户控件不能作为独立文件运行。
【关键代码】WebUserControl.ascx页面代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %> <asp:DropDownList ID="DropDownList1" runat="server"> <asp:ListItem>中国</asp:ListItem> <asp:ListItem>美国</asp:ListItem> <asp:ListItem>日本</asp:ListItem> <asp:ListItem>英国</asp:ListItem> <asp:ListItem>法国</asp:ListItem> <asp:ListItem>加拿大</asp:ListItem> <asp:ListItem>澳大利亚</asp:ListItem> </asp:DropDownList>
习题5-2 在习题5-1的基础上使用用户控件。在网站chapter5_1上添加一个Web页面,命名为Default.aspx。在该页面上使用习题5-1中创建的用户控件,运行结果如图5.10所示。
图5.10 运行结果图
【分析】本题目主要考查的是对用户控件用法的掌握情况。
注意:用户控件在使用之前,必须在页面顶端进行声明,代码如下:
<%@ Register Src =“WebUserControl.ascx” TagName =“WebUserControl” TagPrefix= “DropDownList”%>
习题5-3 在Visual Studio 2012中新建一个网站,命名为chapter5_3。在该网站上添加一个Web页面,命名为Default.aspx。在该Web页面上添加一个DropDownList列表框控件,并为其添加列表项,运行结果如图5.11所示。将该Web页面的内容转换为.ascx文件。
图5.11 运行结果图
【分析】本题目主要考查的是对将.aspx文件内容转换为.ascx文件的方法的掌握情况。
【关键代码】转换后的.ascx文件代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Default.ascx.cs" Inherits="Default" %> <asp:DropDownList ID="DropDownList1" runat="server"> <asp:ListItem>中国</asp:ListItem> <asp:ListItem>美国</asp:ListItem> <asp:ListItem>日本</asp:ListItem> <asp:ListItem>英国</asp:ListItem> <asp:ListItem>法国</asp:ListItem> <asp:ListItem>加拿大</asp:ListItem> <asp:ListItem>澳大利亚</asp:ListItem> </asp:DropDownList>
注意:转换规则参照5.3节。
习题5-4 在Visual Studio 2012中新建一个网站,命名为chapter5_4。在该网站上添加一个Web用户控件文件,命名为WebUserControl.ascx,在该Web用户控件文件的代码后置文件中添加变量和公开属性,使得在Web页面中可以对用户控件进行设置。然后在该网站上添加一个Web页面,命名为Default.aspx。在该页面中将使用用户控件,将用户控件的SelectionMode属性设置为DayWeekMonth。运行结果如图5.12所示。
图5.12 运行结果图
【分析】本题目主要考查的是对编程处理用户控件的掌握情况。
【关键代码】WebUserControl.ascx文件代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %> <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
WebUserControl.ascx.cs文件代码如下:
public partial class WebUserControl : System.Web.UI.UserControl { private DateTime calendardays = DateTime.Now.AddDays(-5); private DateTime calendarselecteddays = DateTime.Now.Date; private CalendarSelectionMode calendarselectionmode = CalendarSelectionMode.Day; protected void Page_Load(object sender, EventArgs e) { Calendar1.TodaysDate = calendardays; Calendar1.SelectedDate = calendarselecteddays; Calendar1.SelectionMode = calendarselectionmode; } public DateTime CalendarDays { get { return calendardays; } set { calendardays = value; } } public DateTime CalendarSelectedDays { get { return calendarselecteddays; } set { calendarselecteddays = value; } } public CalendarSelectionMode CalendarSelectionMode { get { return calendarselectionmode; } set { calendarselectionmode = value; } } }
注意:该示例需要在日历控件中设置CalendarSelectionMode属性的值为DayWeekMonth,并且在Web页面顶端添加使用用户控件的指令。
习题5-5 在Visual Studio 2012中新建一个网站,命名为chapter5_5。在该网站中添加两个用户控件文件,分别命名为WebUserControl.ascx和WebUserControl2.ascx。WebUserControl.ascx文件中使用的是DropDownList控件,WebUserControl2.ascx文件中使用的是Calendar控件。然后添加一个Web页面,命名为Default.aspx,在该页面中添加一个DropDownList控件、一个Button控件和一个PlaceHolder控件。在Button控件的单击事件中动态地加载用户控件,运行结果如图5.13和图5.14所示。
图5.13 运行结果图(1) | 图5.14 运行结果图(2) |
【分析】本题目主要考查的是对动态创建用户控件的掌握情况。
【关键代码】WebUserControl.ascx文件代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits= "WebUserControl" %> <asp:DropDownList ID="DropDownList1" runat="server"> <asp:ListItem>中国</asp:ListItem> <asp:ListItem>美国</asp:ListItem> <asp:ListItem>日本</asp:ListItem> <asp:ListItem>英国</asp:ListItem> <asp:ListItem>法国</asp:ListItem> <asp:ListItem>加拿大</asp:ListItem> <asp:ListItem>澳大利亚</asp:ListItem> </asp:DropDownList>
WebUserControl2.ascx文件代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl2.ascx.cs" Inherits="WebUserControl2" %> <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
Default.aspx.cs文件代码如下:
using System.IO; public partial class _Default : System.Web.UI.Page { private string UserControlPath = "~/"; protected void Page_Load(object sender, EventArgs e) { if (Page.IsPostBack) { if (Session["UserControlFile"] != null) { LoadUserControl((string)Session["UserControlFile"], PlaceHolder1); } } } protected Control LoadUserControl(string ControlPath, PlaceHolder ph) { Control ct1 = Page.LoadControl(ControlPath); ct1.ID = "uid" + Path.GetFileNameWithoutExtension(Server.MapPath(ControlPath)); ph.Controls.Clear(); ph.Controls.Add(ct1); return ct1; } protected void Button1_Click(object sender, EventArgs e) { Session["UserControlFile"] = UserControlPath + DropDownList1.SelectedValue; if (Session["UserControlFile"] != null) { LoadUserControl((string)Session["UserControlFile"], PlaceHolder1); } } }