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

翻译|其它|编辑:郝浩|2005-06-21 10:56:00.000|阅读 1470 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>


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("<Table border='1' width='90%' cellpadding='1'" +
"cellspacing='1' align = 'center' >");
output.Write("<TR><TD colspan = '2' align='center'>");
output.Write("<B> Inquiries </B></TD></TR>");

// 如果没有被包含的控件,输出相应的信息
if (Controls.Count == 0)
{
   output.Write("<TR><TD colspan = '2'> align='center'");
   output.Write("<B> No books listed </B></TD></TR>");
}
// 否则绘制每个包含的控件
else
{
// 遍历控件集,显示每个控件的书名,然后让每个被包含的控件自己绘制自己
for (int i = 0; i < Controls.Count; i++)
{
   current = (BookCounter) Controls[i];
   totalInquiries += current.Count;
   output.Write("<TR><TD align='left'>" +
   current.BookName + "</TD>");
   output.RenderBeginTag("TD");
   current.RenderControl(output);
   output.RenderEndTag( );
   output.Write("</tr>");
}
output.Write("<TR><TD colspan='2' align='center'> " +
" Total Inquiries: " +
     totalInquiries + "</TD></TR>");
  }
    output.Write("</TABLE>");
  }
}


BookInquiryList的VB.NET源代码:

Imports System.ComponentModel
Imports System.Web.UI

<ControlBuilder(GetType(BookCounterBuilder)), ParseChildren(False)> _
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("<Table border='1' width='90%' cellpadding='1'" & _
"cellspacing='1' align = 'center' >")
output.Write("<TR><TD colspan = '2' align='center'>")
output.Write("<B> Inquiries </B></TD></TR>")

' 如果没有被包含的控件,输出相应的信息
If Controls.Count = 0 Then
output.Write("<TR><TD colspan = '2'> align='center'")
output.Write("<B> No books listed </B></TD></TR>")
' 否则绘制每个包含的控件
Else
' 遍历控件集,显示每个控件的书名,然后让每个被包含的控件自己绘制自己
Dim current As BookCounter

For Each current In Controls
totalInquiries += current.Count
   output.Write("<TR><TD align='left'>" & _
   current.BookName + "</TD>")
   output.RenderBeginTag("TD")
   current.RenderControl(output)
   output.RenderEndTag()
   output.Write("</tr>")
Next
Dim strTotalInquiries As String
   strTotalInquiries = totalInquiries.ToString
   output.Write("<TR><TD colspan='2' align='center'> " & _
   " Total Inquiries: " & _
   CStr(strTotalInquiries) & "</TD></TR>")
End If
   output.Write("</TABLE>")
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("<TR><TD align='left'>" +
   current.BookName + "</TD>");
   output.RenderBeginTag("TD");
   current.RenderControl(output);
   output.RenderEndTag( );
   output.Write("</tr>");
}


相应的VB.NET代码为:

For Each current in Controls
   totalInquiries += current.Count
   output.Write("<TR><TD align='left'>" & _
   current.BookName + "</TD>")
   output.RenderBeginTag("TD")
   current.RenderControl(output)
   output.RenderEndTag( )
   output.Write("</tr>")
Next



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

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



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

totalInquiries += current.Count;


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

output.Write("<TR><TD align='left'>" + current.BookName + "</TD>");


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

output.RenderBeginTag("TD");
current.RenderControl(output);
output.RenderEndTag( );
output.Write("</tr>");


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

current.RenderControl(output);


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

查询总数的绘制

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

output.Write("<TR><TD colspan='2' align='center'> " +
" Total Inquiries: " +
totalInquiries + "</TD></TR>");


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

结束语

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

 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP