开发和使用Web用户控件

    在 ASP.NET 的开发中 Web 用户控件的开发和使用是一项必不可少的技术,在对这项技术的一番研究后写下了这篇随笔,不过确实担心这么初级的东东放到原创首页上会被拍砖头。

1.简介
2.创建 Web 用户控件
3.在 Web 窗体中使用 Web 用户控件
4.添加属性
5.添加方法
6.添加自定义事件
7.控件内客户端角本访问服务器控件的方法
8.代码下载


1.简介
    当 ASP.NET 内置的 Web 服务器控件不能满足我们开发的需要时,通过我们会创建自己的控件。而在 ASP.NET 中有两个选择:

    1)用户控件:用户控件是能够在其中放置标记和 Web 服务器控件的容器。然后,可以将用户控件作为一个单元对待,为其定义属性和方法。(这就是咱们这次要讲的啦)
    2)自定义控件:自定义控件是编写的一个类,此类从 Control 或 WebControl 派生。(关于这个方面的技术,目前为止我只按MSDN的演练做了一个练习,后面有时间针对它的开发与使用再写一篇更详细一点的)

    创建用户控件要比创建自定义控件方便很多,因为可以重用现有的控件,所以最适合创建具有复杂界面元素的控件。用户控件与 Web 窗体(.aspx)很相似,可以同时具有前台页面和后台代码,在前台可以向其中添加所需的标签和服务器控件,在后台可以针对这些对象进行逻辑操作。不过它们存在以下这些区别:

    1)用户控件的文件扩展名为 .ascx,而 Web 窗体的扩展名为 .aspx;
    2)用户控件使用 @Control 指令声明,而 Web 窗体使用 @Page 指令;
    3)用户控件不能作为独立文件运行,而必须其它服务器控件一样,将它们添加到 Web 窗体中;
    4)用户控件中不能包含 <html>、<body> 和 <body> 等标签。

2.创建 Web 用户控件

首先建立一个 ASP.NET 网站,如图所示:


在解决方案资源管理器里选中网站,点击右键菜单中的[添加新项],在弹出窗口选择 Web 用户控件,如图所示


点击[添加],在解决方案中可以看到一个新的 Web 用户控件做好了,如图所示:


什么?什么?这就做好了?呵呵,做是做好了,不过没什么功能,现在我们给它加点东西。
编辑TestWebUserControl.ascx,切换到[设计]视图,从工具箱拖动一个 TextBox、一个 Button 和一个 Label 控件到页面上,如图所示:


选中 Button 控件,双击,为其添加 Click 事件的响应代码:
    protected void Button1_Click(object sender, EventArgs e)
    {
        Label1.Text 
= TextBox1.Text;
    }

OK!到此为止,一个简单的 Web 用户控件搞定了。

3.在 Web 窗体中使用 Web 用户控件

现在我们把做好的用户控件放到窗体上进行测试,选中 Default.aspx 切换到[设计]视图(注意:一定要在设计视图里),在解决方案中拖动 TestWebUserControl.ascx 到页面上,如图所示:


现在我们运行程序,在文本框中填入“Hello World!”,点击 Button ,Label 就会显示相应内容了,如图所示:


停止程序,回到 Default.aspx 的[源]视图,我们来看看刚才的“一拖”,IDE到底为我们做了什么工作。可以发现在代码里增加了一行 @Register 指令,这就是对用户控件引用要做的声明,代码如下:
<%@ Register Src="TestWebUserControl.ascx" TagName="TestWebUserControl" TagPrefix="uc1" %>

这个指令很简单,通过字面就可以看出各属性的含义了。现在我们为了使我们的控件前缀更有意义,而不是什么“uc1”之类的,对这条语句做点修改,代码如下:
<%@ Register Src="TestWebUserControl.ascx" TagName="TestWebUserControl" TagPrefix="Clark" %>

当然,相应的其它地方也要进行修改了,如下:

<uc1:TestWebUserControl ID="TestWebUserControl1" runat="server" />
改为
<Clark:TestWebUserControl ID="TestWebUserControl1" runat="server" />

这样,以后我们再在页面使用 TestWebUserControl 控件时前缀自动就变成Clark了,如下所示,我又拖了一个控件到页面里,代码如下:
<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register Src="TestWebUserControl.ascx" TagName="TestWebUserControl" TagPrefix="Clark" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    
<title>无标题页</title>
</head>
<body>
    
<form id="form1" runat="server">
    
<div>
        
<Clark:TestWebUserControl ID="TestWebUserControl1" runat="server" />
        
<br />
        
<Clark:TestWebUserControl ID="TestWebUserControl2" runat="server" />
    
</div>
    
</form>
</body>
</html>

当然,通过在 Web.Config 里进行配置也可以注册组件,并且是针对整个网站适用的,这里就不再述。

4.添加属性

下面我们来为做好的控件添加一个属性,添个什么好呢?(本人最大的弱点就是不会写例子。。。)随便来一个吧,编辑 TestWebUserControl.ascx.cs 添加如下代码:
    public string LabelContext
    {
        
get { return Label1.Text; }
        
set { Label1.Text = value; }
    }

这样一个可读写的文本属性就做好,太简单了。。。

选中 Default.aspx 切换到[设计]视图,分别选中两个用户控件,在属性查看器里对 LabelContext 进行设置,如图所示:


为了测试该属性的实现,我们再在 Default.aspx 的页面上添加一个 Button 控件,对其 Click 事件添加响应代码,如下:
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write(TestWebUserControl1.LabelContext + " " + TestWebUserControl2.LabelContext);

    }

运行程序,点击该按钮,效果如图所示:


5.添加方法

属性加好了,现在再添加一个方法,编辑 TestWebUserControl.ascx.cs ,添加如下代码:
    public void ChangeLabelContext(object sender, string value)
    {
        Label1.Text 
= value;
    }

大家可能注意到,我这个方法有一个 sender ,这是干什么用的呢?别着急,在后面添加事件里会讲到的。

为了测试这个方法,选中 Default.aspx ,切换到[设计]视图,再添加一个按钮,为其 Click 事件添加如下的响应代码:
    protected void Button2_Click(object sender, EventArgs e)
    {
        TestWebUserControl1.ChangeLabelContext(sender, 
"Hi");
        TestWebUserControl2.ChangeLabelContext(sender, 
"cnblogs");
    }

现在运行程序,点击该按钮,效果如图所示:


6.添加自定义事件

属性和方法我们做好了,那么事件呢?
继续编辑 WebUserControlTest.ascx.cs ,首先定义一个代理,代码如下:
public delegate void LabelContextChangedHandler(object sender, LabelContextChangedEventArgs e);

public class LabelContextChangedEventArgs : EventArgs
{
    
private string labelContext;

    
public LabelContextChangedEventArgs(string value)
    {
        labelContext 
= value;
    }
    
public string LabelContext
    {
        
get { return labelContext; }
    }
}

再为 TestWebUserControl 这个类添加一个事件变量和事件触发函数,代码如下:
    public event LabelContextChangedHandler LabelContextChanged;

    
private void OnLabelContextChanged(object sender, LabelContextChangedEventArgs e)
    {
        
if (LabelContextChanged != null)
        {
            LabelContextChanged(sender, e);
        }
    }

然后,在 ChangeLabelContext 函数里增加对事件的触发,需要修改原来的代码,如下:

    public void ChangeLabelContext(object sender, string value)
    {
        Label1.Text 
= value;
    }
改为
    public void ChangeLabelContext(object sender, string value)
    {
        Label1.Text 
= value;
        OnLabelContextChanged(sender, 
new LabelContextChangedEventArgs(value));
    }

OK!到此,我们就完成了对用户控件事件的定义并确定了在何时触发这个事件,下面我们来测试一下。

编辑Default.aspx.cs,先添加一个响应事件的函数,代码如下:
    private void TestWebUserControl_LabelContextChanged(object sender, LabelContextChangedEventArgs e)
    {
        Button tmpButton 
= (Button)sender;
        
if (tmpButton.Text == "Button")
        {
            tmpButton.Text 
= e.LabelContext;
        }
        
else
        {
            tmpButton.Text 
+= " " + e.LabelContext;
        }
    }
实现的效果就是将触发事件的 Button 控件的 Text 属性设置成用户控件 LabelContext 的值。

现在,再在页面的 Page_Load 事件的响应代码里将两个用户近件的 LabelContextChanged 和 这个函数“连接”起来就OK啦!代码如下:
    protected void Page_Load(object sender, EventArgs e)
    {
        TestWebUserControl1.LabelContextChanged 
+= new LabelContextChangedHandler(TestWebUserControl_LabelContextChanged);
        TestWebUserControl2.LabelContextChanged 
+= new LabelContextChangedHandler(TestWebUserControl_LabelContextChanged);
    }

现在我们运行程序,点击页面第二个按钮,效果如图所示这:


7.控件内客户端角本访问服务器控件的方法

这个问题实际上并不属于 Web 用户控件开发的范畴,但实际开发中多多少少会碰到这个问题,所以本着我这“牵牛花”的脾气就把它“牵”进来了,哈哈。

有人要问了,为什么控件内客户端角本访问服务器控件会是一个问题呢,这主要是因为,ASP.NET在将页面解释成客户端浏览器使用的页面时,将用户控件内的服务器控件ID做了一定的改动。如在咱们开发的这个用户控件里有一个 TextBox 控件,ID本来是 TextBox1 ,但在解释后的页面里它变成了 TestWebUserControl1_TextBox1,我们通过在浏览器里查看源代码可以看到,如下所示:
<input name="TestWebUserControl1$TextBox1" type="text" id="TestWebUserControl1_TextBox1" />

也就是说,用户控件被解释成客户端页面后,其中的服务器控件的ID规则是用户控件ID_服务器控件ID,知道这个规律我们就好办了。

编辑 TestWebUserControl.ascx ,切换到[设计]视图,从 HTML 面板拖一个 Input(Button) 控件(注意:这里要的是一个客户端控件)。再切换到[源视图]为其添加 onclick 属性,设成调用一个客户端函数 ShowTextBoxContext ,而这个函数要操作用户控件里的一个服务器控件,完整代码如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="TestWebUserControl.ascx.cs" Inherits="TestWebUserControl" %>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
<input id="Button2" type="button" value="button" onclick="ShowTextBoxContext(<%= TextBox1.ClientID%>)"/>

<script type="text/javascript" language="javascript">
    
function ShowTextBoxContext(obj)
    {
        alert(obj.value);
    }
</script>

注意这里的
<%= TextBox1.ClientID%>,为了获取客户端的对象,我们执行了一个服务端操作,“<%=”和 “%>”之间的代码将会在服务端运行,如此而己,是不是很简单?

现在我们运行程序,在第一个文本框里输入“开发和使用 Web 用户控件,OK!!!”,点击用户控件中刚添加的客户端 Button 按钮,将弹出一个对话框,显示我们填写的内容,效果如图所示:



另:如果使用的是外链角本而非这种内嵌的,那么这种访问方法并不能胜任。我的解决方案是将被访问的服务器控件放到一个 DIV 层里(它本来就是客户端组件),这样在客户端通过先查找到这个 DIV 层,再访问它的处Children 属性,就可以获取到相应的控件了。但由于在用户控件里使用这种外链角本将来在部署上多少有点麻烦,不建议使用,所以就没有列出详细的解决方案。

8.代码下载

下载地址:http://files.cnblogs.com/reonlyrun/WebUserControlTaste.rar


posted @ 2007-03-30 01:30 Clark Zheng 阅读(6364) 评论(44)  编辑 收藏 所属分类: A. .NET

  回复  引用  查看    
#1楼 2007-03-30 02:36 | Jeffrey Zhao      
最大的优点就是“可视化编辑”。
  回复  引用  查看    
#2楼 2007-03-30 02:40 | solog      
8错哦。容易懂就好。
  回复  引用  查看    
#3楼 2007-03-30 08:47 | 亚历山大同志      
用户控件不能跨项目直接重用,其实自定义控件的灵活性更大一些,只不过不能可视化编辑而已,但是可视化真的那么重要么?我们完全可以在Dreamweaver里把界面做好了然后到VS里面来处理,相信很多做网站的人都是不会在VS里面做页面的,一般都是拖拖控件,页面框架早在Dreamweaver里做好了,老实说VS做网页的功能真的很弱质
  回复  引用  查看    
#4楼 2007-03-30 09:01 | ddr888      
学习了。 lz能不能多讲点自定义事件的东西
  回复  引用    
#5楼 2007-03-30 09:05 | 更正楼上 [未注册用户]
@亚历山大同志
是弱智不是弱质。呵呵。
  回复  引用    
#6楼 2007-03-30 09:10 | Mars [未注册用户]
郑兄又写好东西了 受教了
  回复  引用  查看    
#7楼 [楼主]2007-03-30 10:06 | Clark Zheng      
@亚历山大同志
“Visual Studio Orcas 中将提供一个大为改进的HTML和ASP.NET网页设计器。”
引自http://weblogs.asp.net/scottgu/archive/2007/02/08/my-first-look-at-orcas-presentation.aspx

我多么希望美工能在VS里调整部局,而不是把我精心开发的页面拿去修改,回来全乱了套呀。。。
  回复  引用  查看    
#8楼 [楼主]2007-03-30 10:07 | Clark Zheng      
@ddr888
考虑再写一篇随笔。
  回复  引用  查看    
#9楼 [楼主]2007-03-30 10:07 | Clark Zheng      
@Mars
:)
  回复  引用    
#10楼 2007-03-30 11:23 | 任岩彬 [未注册用户]
这个实例真的不错,让我受益很多,好的东西就应当这样深入浅出.
  回复  引用    
#11楼 2007-03-30 12:43 | 周星星 [未注册用户]
能把简单的东西说清楚也非易事。
  回复  引用  查看    
#12楼 2007-03-30 13:15 | 亚历山大同志      
其实我更喜欢把UserControl当作MVC中的View来使用
  回复  引用  查看    
#13楼 2007-03-30 13:18 | 垃圾猪      
@亚历山大同志
可以做到可视化的,自定义控件可绑定Designer呈现
  回复  引用  查看    
#14楼 2007-03-30 14:20 | Clingingboy      
其实自定义控件可视化可以做的更好,但用户控件也可以做到的,区别最大还是可否跨项目使用吧.
  回复  引用  查看    
#15楼 2007-03-30 15:27 | 金色海洋(jyk)      
自定义控件是不是也差不多呀,我想写自定义控件。这样可以跨项目。

  回复  引用  查看    
#16楼 [楼主]2007-03-30 15:43 | Clark Zheng      
@任岩彬
@周星星

谢谢支持
  回复  引用  查看    
#17楼 [楼主]2007-03-30 15:46 | Clark Zheng      
@Clingingboy
@金色海洋(jyk)

个人认为,用户控件也可以跨项目用,直接拷过去,嘿嘿。
控件嘛,本来就是通过封装提供一定的去耦和复用。
  回复  引用  查看    
#18楼 2007-03-30 17:28 | Clingingboy      
@金色海洋(jyk)
不嫌弃的话,可以参考我博客的文章

  回复  引用    
#19楼 2007-03-30 17:53 | 火狐 [未注册用户]
有价值呀,好东西。
  回复  引用  查看    
#20楼 2007-03-30 18:16 | e表      
楼主辛苦了!! (纯.net写的web报表设计工具: http://ebiao.cnblogs.com/ )
  回复  引用    
#21楼 2007-03-30 19:30 | 桂圆 [未注册用户]
通俗易懂 不错啊
  回复  引用  查看    
#22楼 2007-03-31 09:37 | wddavid      
现在做网页也是用DIV+CSS吧,谁还用DREAMWEAVER在里面拖拉?
  回复  引用  查看    
#23楼 2007-04-02 12:57 | 公木子      
很容易懂
  回复  引用    
#24楼 2007-04-02 22:06 | liu [未注册用户]
如何给传递变量到自定控件的html控件上呢
  回复  引用  查看    
#25楼 [楼主]2007-04-02 22:13 | Clark Zheng      
@liu
html控件的ID不会变化,不管是在页面里还是在用户控件里,所以直接获取该元素对其进行操作即可
  回复  引用    
#26楼 2007-07-15 03:05 | gerbil [未注册用户]
谢谢楼主...学习了...
  回复  引用    
#27楼 2007-07-20 06:29 | 火狐 [未注册用户]
5. ASP.NET 2.0 本地化技术之研究(二)(20)

  回复  引用    
#28楼 2007-07-20 06:29 | 火狐 [未注册用户]
现在做网页也是用DIV+CSS吧,谁还用DREAMWEAVER在里面拖拉?
  回复  引用    
#29楼 2007-07-20 06:30 | 火狐 [未注册用户]
控件内客户端角本访问服务器控件的方法
  回复  引用    
#30楼 2007-08-19 09:56 | Sue [未注册用户]
谢谢楼主,受益非浅,学习中... ...
  回复  引用    
#31楼 2007-09-19 14:27 | kingren [未注册用户]
值得学习,谢谢LZ
  回复  引用    
#32楼 2007-09-25 15:35 | kingren [未注册用户]
再次感谢LZ。
深入浅出,极具代表性 ,非常好!
  回复  引用    
#33楼 2007-10-19 15:27 | 多发 [未注册用户]
辛苦了!谢谢!
  回复  引用    
#34楼 2007-10-26 13:31 | 火狐 [未注册用户]
好,有技术
  回复  引用    
#35楼 2008-03-24 12:32 | yangedie [未注册用户]
谢谢博主,讲的通俗易懂,并且还有源代码下
  回复  引用    
#36楼 2008-05-11 19:31 | mengxj85 [未注册用户]
很好,拿走了
  回复  引用  查看    
#37楼 2008-05-14 11:54 | Longkin      
下载的与上面写的不一样呢?
  回复  引用  查看    
#38楼 [楼主]2008-05-14 13:44 | Clark Zheng      
@Longkin
不会吧,哪里不一样?
  回复  引用    
#39楼 2008-05-22 15:51 | 好 [未注册用户]
夸一下,谢一下
  回复  引用    
#40楼 2008-06-21 09:51 | 不不 [未注册用户]
您好,两个用户控件应该怎么样用呀?比如我想在一个用户控件单击登录成功之后,把另一个用户控件的asp:panl隐藏了,就应该怎么做呀?
  回复  引用    
#41楼 2008-06-29 22:05 | sunxitao88 [未注册用户]
很好,学习了.楼主辛苦
  回复  引用  查看    
#42楼 2008-08-12 13:26 | 不妨沉迷      
请问如何引用不同项目里的用户控件~?
  回复  引用  查看    
#43楼 [楼主]2008-08-12 16:01 | Clark Zheng      
@不妨沉迷
好象不行,用户控件有局限性,只能在本项目中被引用,改用自定义控件吧

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-09-12 17:56 编辑过
成果网网络广告联盟


相关链接: