zoukankan      html  css  js  c++  java
  • UserControl 用户自定义控件

    关于用户自定义控件,想必大家已经非常熟悉了。虽然说经常用过,但是只是简单的使用而已。在这里再次总结一下Asp.net中的UserControl,以便下次使用时

    能够得心应手。本文将会介绍以下内容:


    1,什么是UserControl?
    2,如何定义一个UserControl?
    3,如何使用UserControl?
    4,如何通过UserControl属性来控制html?
    5,如何实现<u1:Control>string</u1:Control>?

     

    1,什么是UserControl?

     

    关于UserControl的解释MSDN,跟Wikipedia都有介绍:

    http://msdn.microsoft.com/en-us/library/system.web.ui.usercontrol.aspx
    http://en.wikipedia.org/wiki/ASP.NET#User_controls

    说白了,UserControl的存在就是为了重用html代码。有点类似php的include或者require,但是它比include或require更加灵活,它不当只是
    单纯的引入代码,而且通过设置UserControl的属性来对html代码进行控制,从而更好的实现代码复用。基本UserControl的使用方法更aspx页面
    是一样的,但是UserControl不可以通过url来访问,只能在页面或者其它用户控件中访问。

    2,如何定义一个简单UserControl?

     
    新建UserControl方法:右键asp.net web项目->添加->添加新项->Web->Web用户控件。打开控件的后台代码,我们可以看到,控件
    继承于System.Web.UI.UserControl类。新建好的控件除了后缀名更asp.net不同之外,其它结构都一样,用法也基本一致。
    这是,你就可以在ascx文件添加html代码了。

    3,如何使用UserControl?

     


    在页面中使用UserControl只需要在页面的头部添加Register代码段:
    <%@ Register src="UserControl/UC_Demo.ascx" tagname="Demo" tagprefix="uc1" %>
    src表示用户控件所在的相对路径。
    添加完上述代码段之后,就可以你需要使用的地方使用了。
    使用方法如下,我们可以看到uc1就是上面定义的tagprefix,Demo就是上面定义的tagname,由于用户控件也是一种服务端控件
    因此我们这里必须加上runat="server",否则.net会认为是html标签。
    <uc1:Demo ID="aaa" runat="server">
    </uc1:Demo>

    4,如何自定义属性来控制UserControl的html?

     
    第2,3部分已经介绍了如何新建以及使用一个简单的用户控件。但是,上面的例子只能满足对于简单html的复用,比如说一些
    头部信息或底部信息。但对于一些复杂的模块,显然我们需要一些属性来控制它。比如说:我们定义一个用户控件,
    该控件需要用户可以自定义主题。即用户希望能够这样的使用:
    <uc1:Demo ID="aaa" ThemeName="green" runat="server">
    </uc1:Demo>

    那么该怎么实现呢?首先,我们的第一印象就是,Theme应该是一个enum类型,可供用户选择,因此,我们首先定义一个Theme的枚举
       

    public enum Theme
    {
         Brown = 10,
         Cyan = 20,
         Gray = 30,
         Green = 40,
          Leaf = 50,
          Plain = 60,
          Purple = 70
    }
    

        
     OK,枚举有了,那么我们应该如何将该枚举变成UserControl中可设置的选项呢?在UserControl的后台代码中(即ascx.cs文件),
     我们只需为该控件类定义一个public的共有变量即可。因此,我们只要在后台类文件中,添加如下代码就可以实现上述需要:
     public Theme ThemeName;
     我们可以通过私有成员来设置初始值,这时候代码就变成这样:

    private Theme _ThemeName = Theme.Cyan;
    
    public Theme ThemeName
    {
         get { return this._ThemeName; }
         set { _ThemeName = value; }
    }
    
    

    此时,用户可以通过属性来设置Theme了,Theme在页面中设置后,用户控件就可以通过Theme来控制它的html代码中的样式了。

    5,如何实现<u1:Control>string</u1:Control>?

     
    这个是本文中要讲的重点。在使用用户控件的过程中,有时候是一个模块(如下图),我只需要重用这个框,而这个框里的内容
    是要自定义的。那么我们要怎么办呢?首先我们想到的是属性,但是我们不可能将一大串的html代码作为属性传递过去,
    这样代码就太恶心了。因此我们就想到了标题的那种方式。将html夹在控件中间。还是接着上面所说的例子,这时,我们希望
    用户可以这样调用:

    <uc1:Demo ID="aaa" ThemeName="green" runat="server">
     <div style="100px;height:100px;backgroud:red;">
      hello world!
     </div>
    </uc1:Demo>
    

    通过google,我找到了解决办法。asp.net提供了ITextControl接口,通过该接口我们就可以实现上述的功能。因此,我们需要做的
    就是:第一步,让UserControl实现ITextControl接口。第二步,实现ITextControl的Text字段。第三步,重写Control类中的AddParsedSubObject方法。

    假设我们有好几个这样的控件,因此,我们将以上三步实现的内容抽象到一个类中,我们暂且叫做DemoWidget,代码如下:

      [ParseChildren(false)]
        public class DemoWidget : System.Web.UI.UserControl, ITextControl
        {
            [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
            public virtual string Text
            {
                get
                {
                    object obj2 = this.ViewState["Text"];
                    if (obj2 != null)
                    {
                        return (string)obj2;
                    }
                    return string.Empty;
                }
                set
                {
                    if (this.HasControls())
                    {
                        this.Controls.Clear();
                    }
                    this.ViewState["Text"] = value;
                }
            }
    
            protected override void AddParsedSubObject(object obj)
            {
                if (obj is LiteralControl)
                {
                    HtmlContent.Append(((LiteralControl)obj).Text);
                    this.Text = HtmlContent.ToString();
                }
                else
                {
                    if (obj != null)
                    {
                        HtmlContent.Append(GetControlHtml(obj as Control));
                        this.Text = HtmlContent.ToString();
                    }
                }
            }
            protected StringBuilder HtmlContent = new StringBuilder();
            protected string GetControlHtml(Control ctl)
            {
                StringBuilder sb = new StringBuilder();
                StringWriter tw = new StringWriter();
                HtmlTextWriter writer = new HtmlTextWriter(tw);
                ctl.RenderControl(writer);
                sb.Append(writer.InnerWriter.ToString());
                return sb.ToString();
                //base.AddParsedSubObject(new LiteralControl(tmpStr));
                //this.Text = tmpStr;
            }
        }
    
    
    

    我们来看一下,DemoWidget是如何实现上述的三个步骤的。很明显第一步已经完成。

    第二步我们可以看到也实现了ITextControl的Text字段,Text字段就是用于保存夹在用户控件中间的文本,从代码中我们可以看到,我将这些文本信息保存到viewstate中。
    而Text上方的属性[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    又表示什么呢?msdn的解释如下:
    InnerDefaultProperty 指定属性在 ASP.NET 服务器控件中保持为内部文本。还指示将该属性定义为元素的默认属性。只能指定一个属性为默认属性。
    http://msdn.microsoft.com/zh-cn/library/system.web.ui.persistencemode.aspx
    也就是说,Text将作为DemoWidget的默认属性使用,而且只能有一个这样的属性。

    第三步,重写AddParsedSubObject方法
    为什么要重新AddParsedSubObject方法呢?我们首先添加一个空的AddParsedSubObject方法,设置一个断点,然后调试,我们可以发现,当DemoWidget中间有文本时,
    都会调用该函数,因此,这里我们可以将html赋值给Text。默认,传递进该函数的对象是LiteralControl类型的。因此我们实现如下代码:
    该方法的具体解释请查看msdn:http://msdn.microsoft.com/zh-cn/library/system.web.ui.control.addparsedsubobject.aspx
     protected override void AddParsedSubObject(object obj)
     {
       if (obj is LiteralControl)
        {
             this.Text = ((LiteralControl)obj).Text;
        }
     }
     
     这里还需要注意的是:我们必须为DemoWidget类添加属性[ParseChildren(false)],ParseChildren属性表示是否将服务器控件标记内的元素解释为属性,因此,这里应该为false。
     http://msdn.microsoft.com/zh-cn/library/system.web.ui.parsechildrenattribute.aspx
     
     好了,之前提到的三步我们都已经完成了,可是我发现类还有其它代码,其它代码又是干嘛的呢?此时,我们发现如果刚刚三步虽实现了一开始提出的需求,
     但是,上述类还有一定的局限性,就是控件标记内只能包含html文本,当控件标记内需要包含另外一个控件的时候就有问题了。

     <uc1:Demo ID="aaa" ThemeName="green" runat="server">
     <div style="100px;height:100px;backgroud:red;">
      hello world!
     </div>
     <uc1:Demo ID="bbb" ThemeName="Leaf" runat="server">
      <div style="100px;height:100px;backgroud:red;">
       hello world!
      </div>
     </uc1:Demo>
    </uc1:Demo>
    
    

    由于控件标记中包含了其它控件,因此,AddParsedSubObject中的参数obj就有可能是子控件类型,因此我们必须修改AddParsedSubObject函数,并新建HtmlContent成员,用于保存子控件的html代码
    然后再将该子控件生成的html代码赋值给控件的Text属性,GetControlHtml方法就是用于获取子控件生成的html代码。而AddParsedSubObject则变成如下所示:

      

      protected override void AddParsedSubObject(object obj)
            {
                if (obj is LiteralControl)
                {
                    HtmlContent.Append(((LiteralControl)obj).Text);
                    this.Text = HtmlContent.ToString();
                }
                else
                {
                    if (obj != null)
                    {
                        HtmlContent.Append(GetControlHtml(obj as Control));
                        this.Text = HtmlContent.ToString();
                    }
                }
            }
    
    

           
    这时,你就可以随意在UserControl标签里添加任何东西了,你可以添加html代码,也可以添加自定义控件,甚至还可以添加asp.net服务端控件。

    嗯,关于UserControl的内容就介绍到这里,有什么讲得不对的地方请大家指正,同时也期望得到大家的鼓励。

    这里是源代码

  • 相关阅读:
    Atmel Studio 烧录 Atmega328P(Arduiono)
    JSP内置对象详解及示例
    Hash Map 详细解释及示例
    19年双非学长逆袭985考研经验贴
    camelCase命名规范
    开始我的编程之旅!
    【转】堆和栈的区别
    现场编写类似strstr/strcpy函数
    【转】C++多态篇1一静态联编,动态联编、虚函数与虚函数表vtable
    【转】TCP协议中的三次握手和四次挥手(图解)
  • 原文地址:https://www.cnblogs.com/coolkiss/p/1820467.html
Copyright © 2011-2022 走看看