您的位置:首页精文荟萃软件资讯 → ASP.NET 定制控件的开发(二)

ASP.NET 定制控件的开发(二)

时间:2004/10/7 18:10:00来源:本站整理作者:蓝点我要评论(0)

 复合控件的创建

创建定制控件的第三种方法是组合二个或二个以上的现有的控件。在下面的例子中,读者将以合同编程人员的身份出现,而我则是客户,我希望读者能够开发一个稍微复杂一些的控件,使我能够用来记录收到的对我的书的询价。

作为客户,我将要求读者开发一个控件,使我能够输入一本或多本书籍,每当点击一本书时,控件就会记录下对该书的点击次数,如下图所示:
 

 



这一程序的.aspx文件如下所示,除@ Page命令外,该程序的C#和VB程序是相同的:

利便控件的.aspx文件


 
 
 
 
 
     
 
 
 
 
     
 
 
 
               

 
   
 



在上面的代码中需要注意的是,BookInquiryList组件中包含许多BookCounter元素,其中有一个BookCounter元素是对应着我希望记录的书籍。这个控件非常灵活,我可以对任意数量的书进行记录。每个BookCounter元素有一个用来显示被记录书籍名字的BookName属性。

从图9中我们可以看到,每本书都由一个CountedButton定制控件进行记录,但.aspx文件中没有CountedButton控件的定义,它被完整地封装在了BookCounter定制控件中。

整个体系结构如下所示:


 


  1. BookInquiry利便控件是由WebControl派生的,实现了INamingContainer,在下面我们会提到。
     
  2. BookInquiry控件有一个由Control类派生的Controls特性。
     
  3. 在控件集合中有数量不等的BookCounter控件。
     
  4. BookCounter本身也是一个由WebControl派生得来的复合控件,WebControl也实现了INamingContainer。

    1. BookContainer的每个实例有二个特性:BookName和Count。
       
    2. Name特性是由Viewstate支持的,而且通过.aspx文件中的BookName BookName初始化。
       
    3. Count特性授权给private性质的CountedButton对象



使用BookInquiry对象的目的有二个:它是BookCounter对象的容器;它负责绘制它本身并确保它包含的BookCounter对象能够按需求绘制自己。

CountedButton控件的修改

我们需要对CountedButton控件进行一些很小的修改,下面分别是C#和VB.NET版的CountedButton控件。

修改后的CountedButton.cs文件


 


using  System;
  using  System.Web.UI;
  using  System.Web.UI.WebControls;
  using  System.ComponentModel;
 
  namespace  CustomControls
  {
        //  由System.Web.UI.WebControls.Button派生出的定制控件
        public  class  CountedButton  :  System.Web.UI.WebControls.Button
        {
 
              private  string  displayString;
 
              //  缺省的构造器
              public  CountedButton(    )
              {
                    displayString  =  "clicks";
                    InitValues(    );
              }
 
              //  重载,显示字符串
              public  CountedButton(string  displayString)
              {
                    this.displayString  =  displayString;
                    InitValues(    );
              }
 
              //  由构造器调用的函数
              private  void  InitValues(    )
              {
                    if  (ViewState["Count"]  ==  null)
                          ViewState["Count"]  =  0;
                    this.Text  =  "Click  me";
              }
 
              //  Count是ViewState中的一个特性
              public  int  Count 
            {
                  get
                  {
                        //  在构造器中初始化,不能是NULL
                          return  (int)  ViewState["Count"];
                    }
 
                    set
                    {
                          ViewState["Count"]  =  value;
                    }
              }
 
              //  覆盖OnClick事件处理程序,增大Count变量的值,并在更新按钮上的文本后调用基础类中的方法
              protected  override  void  OnClick(EventArgs  e)
              {
                    ViewState["Count"]  =    ((int)ViewState["Count"])  +  1;
                    this.Text  =  ViewState["Count"]  +  "  "  +  displayString;
                    base.OnClick(e);
              }
        }
  }



修改后的CountedButton.vb文件


 


Imports  System.ComponentModel
  Imports  System.Web.UI
  Imports  System.Web.UI.WebControls
 
  '  从System.Web.UI.WebControls.Button中派生的定制控件
  Public  Class  CountedButton
        Inherits  System.Web.UI.WebControls.Button
 
        Private  displayString  As  String
 
        '  构造器对ViewState进行初始化
        Public  Sub  New(    )
              displayString  =  "clicks"
              Init(    )
        End  Sub
 
      '  重载,显示字符串
        Public  Sub  New(ByVal  displayString  As  String)
              Me.displayString  =  displayString
              Init(    )
        End  Sub
 
        '  由构造器调用的方法
        Private  Shadows  Sub  Init(    )
              If  ViewState("Count")  =  Is  Nothing  Then
                    ViewState("Count")  =  0
                    Me.Text  =  "Click  me"
              End  If
        End  Sub
 
        '  Count是ViewState中的一个特性
        Public  Property  Count(    )  As  Integer
              Get
                    Return  CInt(ViewState("Count"))
              End  Get
              Set(ByVal  Value  As  Integer)
                    ViewState("Count")  =  Value
              End  Set
        End  Property
 
        '    覆盖OnClick事件处理程序,增大Count变量的值,并在更新按钮上的文本后调用基础类中的方法
        Protected  Overrides  Sub  OnClick(ByVal  e  As  EventArgs)
              ViewState("Count")  =  CInt(ViewState("Count"))  +  1
              Me.Text  =  CStr(ViewState("Count")  &  "  "  &  displayString
              MyBase.OnClick(e)
        End  Sub
  End  Class?)



由于我们希望按钮上显示“5 Inquiries”而不是“5 clicks”字符串,因此必须修改OnClick方法中修改按钮字符串文本的代码:


 

this.Text = ViewState["Count"] + " " + displayString;



相应的VB.NET代码是:


 

Me.Text = ViewState("Count") & " " & displayString



我们还使用了一个private性质的成员变量displayString来存储传递给构造器中的数值:


 

private string displayString;



在VB.NET中的代码为:


 

Private displayString As String



我们必须在构造器中设置这一字符串。为了保护已经使用了缺省的构造器的代码,我们必须重载构造器,新增加一个带有字符串参数的构造器:


 

public  CountedButton(string  displayString)
    {
          this.displayString  =  displayString;
          Init(    );
    }
 



在VB.NET中的代码是:


 

Public  Sub  New(ByVal  displayString  As  String)
        Me.displayString  =  displayString
        Initialize(    )
  End  Sub
 



我们可以对缺省的构造器进行修改,将displayString成员变量有值设置为一个合理的缺省值。其C#代码如下:


 

public  CountedButton(    )
  {
        displayString  =  "clicks";
        InitValues(    );
  }



相应的VB.NET代码是:


 


Public  Sub  New(    )
        displayString  =  "clicks"
        Init(    )
  End  Sub

 

 



二个构造器的代码都没有考虑private性质的辅助方法Init,它能够保证Count特性被初始化为0,并设置最初时按钮显示的字符串:


 

private  void  Init(    )
  {
        if  (ViewState["Count"]  ==  null)
              ViewState["Count"]  =  0;
        this.Text  =  "Click  me";
  }



在VB.NET中,相应的代码为:


 


Private  Shadows  Sub  Init(    )
        If  ViewState("Count")  =  Nothing  Then
              ViewState("Count")  =  0
              Me.Text  =  "Click  me"
        End  If
  End  Sub



作了上述的修改后,我们就可以在第一个复合控件━━BookCounter中使用CountedButton了。

BookCounter复合控件的创建

BookCounter复合控件用于记录和显示对某一本书查询的次数,下面分别是C#和VB.NET版的BookCounter复合控件的源代码:

C#版本的BookCounter控件源文件:BookCounter.cs


 


using  System;
  using  System.Web.UI;
  using  System.Web.UI.WebControls;
  using  System.ComponentModel;
 
  namespace  CustomControls
  {
        public  class  BookCounter  : 
            System.Web.UI.WebControls.WebControl, 
            INamingContainer
      {

            //  初始化按钮成员
              CountedButton  btn  =  new  CountedButton("inquiries");
 
              public  string  BookName 
            {
                  get
                  {
                        return  (string)  ViewState["BookName"];
                    }
 
                    set
                    {
                          ViewState["BookName"]  =  value;
                    }
              }
 
              public  int  Count
              {
                    get
                    {
                          return  btn.Count;
                    }
                    set
                    {
                          btn.Count  =  value;
                    }
              }
 
              public  void  Reset(    )
              {
                    btn.Count  =  0;
              }
 
              protected  override  void  CreateChildControls(    )
              {
                    Controls.Add(btn);
              }
        }
  }



VB.NET版的BookCounter控件的源代码: BookCounter.vb


 


Imports  System
  Imports  System.Web.UI
  Imports  System.Web.UI.WebControls
  Imports  System.ComponentModel
 
  Public  Class  BookCounter
        Inherits  System.Web.UI.WebControls.WebControl
        Implements  INamingContainer
 
        '  初始化按钮成员
        Public  btn  As  CountedButton  =  New  CountedButton("inquiries")
 
        Public  Property  BookName(    )  As  String
              Get
                    Return  CStr(ViewState("BookName"))
              End  Get
              Set(ByVal  Value  As  String)
                    ViewState("BookName")  =  Value
              End  Set
        End  Property
 
        Public  Property  Count(    )  As  Integer
              Get
                    Return  btn.Count
              End  Get
              Set(ByVal  Value  As  Integer)
                    btn.Count  =  Value
              End  Set
        End  Property
 
        Public  Sub  Reset(    )
              btn.Count  =  0
        End  Sub
 
        Protected  Overrides  Sub  CreateChildControls(    )
              Controls.Add(btn)
        End  Sub
 
  End  Class
 



INamingContainer

BookCounter类中首先需要注意的是它实现了INamingContainer界面,这是一个没有方法的“记分器”界面。这一界面的目的是识别创建新的ID名字空间的容器控件,保证所有的子控件都有对于应用程序是唯一的ID。

包含CountedButton

BookCounter类包含有CountedButton的一个实例:


 

CountedButton btn = new CountedButton("inquiries");



或:


 

Public btn As CountedButton = New CountedButton("inquiries")



btn成员是在由System.Control继承的CreateChildControls方法中被初始化的:


 

protected  override  void  CreateChildControls(    )
  {
        Controls.Add(btn);
  }
 



在VB.NET中,相应的代码为:


 


Protected  Overrides  Sub  CreateChildControls(    )
        Controls.Add(btn)
  End  Sub



CreateChildControls是在绘制的准备工作时被调用的,它使BookCounter类能够添加btn对象作为被包含的控件。

BookCounter无需覆盖Render方法,它唯一需要绘制的是CountedButton。Render缺省的操作是绘制所有的子控件,因此无需对它作任何修改就能完成其功能。

BookCounter还有二个特性:BookName和Count。BookName是在控件中显示的一个字符串,而且通过ViewState进行管理,其C#代码如下所示:


 


public  string  BookName 
{
        get
        {
                return  (string)  ViewState["BookName"];
          }
 
          set
          {
                  ViewState["BookName"]  =  value;
          }
  }



相应的VB.NET源代码为:


 


Public  Property  BookName(    )  As  String
        Get
              Return  CStr(ViewState("BookName"))
        End  Get
        Set(ByVal  Value  As  String)
              ViewState("BookName")  =  Value
        End  Set
  End  Property



Count是对一本特定的书查询的数量,记录这一数量的任务由CountedButton完成。其C#代码如下所示:


 

public  int  Count
  {
        get
        {
              return  btn.Count;
        }
        set
        {
              btn.Count  =  value;
        }
  }



相应的VB.NET源代码为:


 


Public  Property  Count(    )  As  Integer
        Get
              Return  btn.Count
        End  Get
        Set(ByVal  Value  As  Integer)
              btn.Count  =  Value
        End  Set
  End  Property



无需将该值放在ViewState中,因为按钮本身就可以对其数据进行管理。

BookInquiryList复合控件的创建

每个BookCounter对象都被包含在BookInquiryList控件集合中,该控件没有特性,只有一个Render方法,其C#和VB.NET代码如下所示:

BookInquiryList的C#代码:


 


[ControlBuilderAttribute(typeof(BookCounterBuilder)),ParseChildren(false)]
public  class  BookInquiryList  :  System.Web.UI.WebControls.WebControl,  INamingContainer
  {
 
        protected  override  void  Render(HtmlTextWriter  output)
        {
              int  totalInquiries  =  0;
              BookCounter  current;
 
              //  输出头部
              output.Write("                    "cellspacing='1'  align  =  'center'  >");
              output.Write("

");
        }
  }

BookInquiryList的VB.NET源代码:


 

Imports  System.ComponentModel
  Imports  System.Web.UI
 
    _
  Public  Class  BookInquiryList
        Inherits  System.Web.UI.WebControls.WebControl
        Implements  INamingContainer
 
        Protected  Overrides  Sub  Render(ByVal  output  As  HtmlTextWriter)
 
              Dim  totalInquiries  As  Integer  =  0
 
              '  输出头部
              output.Write("                    "cellspacing='1'  align  =  'center'  >")
              output.Write("

")
        End  Sub
 
  End  Class
 
  Friend  Class  BookCounterBuilder
        Inherits  ControlBuilder
 
        Public  Overrides  Function  GetChildControlType(  _
                    ByVal  tagName  As  String,  ByVal  attributes  As  IDictionary)  As  Type
              If  tagName  =  "BookCounter"  Then
                    Dim  x  As  BookCounter
                    Return  x.GetType
              Else
                    Return  Nothing
              End  If
        End  Function
 
        Public  Overrides  Sub  AppendLiteralString(ByVal  s  As  String)
        End  Sub
 
  End  Class

ControlBuilder和ParseChildren属性

BookCounter类必须与BookInquiryClass联合使用,ASP.NET才能将.aspx网页中的元素转换为适当的代码。完成这一工作需要用到ControlBuilder属性:

[ControlBuilderAttribute(typeof(BookCounterBuilder)),ParseChildren(false)]

ControlBuilderAttribute的参数是一个通过传递BookCounterBuilder类获取的Type对象。下面是使用C#和VB.NET编写的BookCounterBuilder源代码:

C#语言版的BookCounterBuilder


 

internal  class  BookCounterBuilder  :  ControlBuilder
  {
        public  override  Type  GetChildControlType(
              string  tagName,  IDictionary  attributes)
        {
              if  (tagName  ==  "BookCounter")
                    return  typeof(BookCounter);
              else
                    return  null;
        }
 
        public  override  void  AppendLiteralString(string  s)
        {
        }
  }
 
  VB.NET版的BookCounterBuilder 

Friend  Class  BookCounterBuilder
          Inherits  ControlBuilder
 
          Public  Overrides  Function  GetChildControlType(_
                  ByVal  tagName  As  String,  ByVal  attributes  As  Idictionary)  As  Type
              If  tagName  =  "BookCounter"  Then
                  Dim  x  As  BookCounter
                  Return  x.GetType
              Else
                  Return  Nothing
              End  If
          End  Function
 
          Public  Overrides  Sub  AppendLiteralString(ByVal  s  As  String)
          End  Sub
 
  End  Class



ASP.NET将使用由ControlBuilder中派生出的BookCounterBuilder来判断由BookCounter标记批指示的对象的类型。通过这种结合,每个BookCounter对象才能被实例化,并添加到BookInquiryClass的控件集合中。

第二个参数ParseChildren必须被设置成false,让ASP.NET知道我们已经对子属性进行了处理,无需再对它进行进一步地解析了。false值表明子属性不是外部对象的特性,而仅仅是子控件的特性。

Render

BookInquiryClass中的唯一方法是覆盖Render的方法,Render的作用是使用由每个BookCounter子控件管理的数据绘制图9中的表格。

BookInquiryClass提供了一个总的查询数字,如下图所示:


 



Figure 14-16. Total inquiries displayed

通过将totalInquiries整型变量初始化为0,然后依次遍历每个控件,将其Count特性与totalInquiries相加,就可以得到查询的总数了。除了C#中语句结束时的分号为,实现这一功能的C#和VB.NET语句相同:

totalInquiries += current.Count;

表现输出内容

通过遍历每个控件,下面的代码能够绘制出每个子控件:


 

for  (int  i  =  0;  i  <  Controls.Count;  i++)
  {
        current  =  (BookCounter)  Controls[i];
        totalInquiries  +=  current.Count;
        output.Write("



相应的VB.NET代码为:


 

For  Each  current  in  Controls
        totalInquiries  +=  current.Count
        output.Write("



局部的BookCounter对象型current变量的值被赋为控件集合中的每个对象:


 

for  (int  i  =  0;  i  <  Controls.Count;  i++)
  {
        current  =  (BookCounter)  Controls[i];
 



然后就可以利用下面的代码计算totalInquiries:


 

totalInquiries += current.Count;



然后我们就可以继续绘制对象了。通过利用current的BookName特性,HtmlTextWriter可以用来创建一个行并显示书的名字:


 

output.Write("
" + current.BookName + "



接下来,我们绘制一个TD标记,在该标记内我们让BookCounter对象绘制自己。最后,使用RenderEndTag来绘制一个结束性的TD标记,并使用HTMLTextWriter的Write方法绘制行结束标记。


 

output.RenderBeginTag("TD");
  current.RenderControl(output);
  output.RenderEndTag(    ); 
  output.Write("



下面的代码使被包含的控件自己绘制自己:


 

current.RenderControl(output);



上面的代码会调用BookCounter的Render方法。由于我们没有覆盖该方法,调用的仍然是基础类中的Render 类。唯一被包含的对象是CountedButton,由于我们没有覆盖CountedButton中的Render方法,在绘制该按钮时调用的仍然是基础类Button中的Render方法。

查询总数的绘制

所有的子控件绘制完毕后,BookInquiryList将创建一个新的行,显示总的查询次数:


 

output.Write("



至此,作为合同编程人员的你,就完成了任务。

结束语

在上面的文章中,我们讨论了开发定制控件的三种途径,尤其是通过一个例子,详细论述了建立复合控件的过程。在具体的工作中,灵活地运用这三种方式创建定制控件,使我们的开发工作事半功倍。

 

相关阅读 Mac访问Windows共享文件夹Windows 7正版系统验证方法windows 8.1系统版本号查看方法Windows 8.1系统电话激活时无法输入微软返回代码解决方法Windows 8如何调整屏幕分辨率windows8.1磁盘占用100%解决方法Mac双系统如何删除Boot Camp安装的Windows分区Apple教你如何在Mac 上运行 Windows

文章评论
发表评论

热门文章 360随身Wifi 4G版什么怎样提高origin下载速百度收购PPS已敲定!3

最新文章 伊森卡特的消失通关流千牛怎么设置自动回复 增加新功能,S版Moto G喜获Android 4.4.4更鸡肋?谷歌Play Music发布更新版本千牛怎么设置自动回复​千牛云盘怎么用

人气排行 xp系统停止服务怎么办?xp系统升级win7系统方office2013安装教程图解:手把手教你安装与同步推是什么?同步推使用方法介绍QQ2012什么时候出 最新版下载VeryCD镜像网站逐个数,电驴资料库全集利用PHP程序设定防止MySQL注入或HTML表单滥web服务器和应用服务器的区别安卓android 系统支持什么视频格式