WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

Programming ASP.NET: Custom and User Controls, Part 2
Pages: 1, 2, 3, 4, 5

Properties

Custom controls can expose properties just as any other class can. You access these properties either programmatically (e.g., in code-behind) or declaratively, by setting attributes of the custom control, as you did in the text page, and as shown here:

<OReilly:WebCustomControl1 Runat="Server" Text="Hello World!" />

The Text property of the control is accessed through the Text attribute in the web page.

In the case of the Text property and the Text attribute, the mapping between the attribute and the underlying property is straightforward because both are strings. ASP.NET will provide intelligent conversion of other types, however. For example, if the underlying type is an integer or a long, the attribute will be converted to the appropriate value type. If the value is an enumeration, ASP.NET matches the string value against the evaluation name and sets the correct enumeration value. If the value is a Boolean, ASP.NET matches the string value against the Boolean value; that is, it will match the string "True" to the Boolean value true.

The Render method

The key method of the custom control is Render. This method is declared in the base class, and must be overridden in your derived class if you wish to take control of rendering to the page. In Examples 14-8 and 14-9, the Render method uses the HtmlTextWriter object passed in as a parameter to write the string held in the Text property.

The HtmlTextWriter class derives from TextWriter and provides rich formatting capabilities. HtmlTextWriter will ensure that the elements produced are well-formed, and it will manage the attributes, including style attributes. Thus, if you want to set the text to red, you can add a color attribute, passing in an enumerated color object that you've translated to HTML, as shown here:

output.AddStyleAttribute("color", ColorTranslator.ToHtml(Color.Red));

You can set the text to be within header (<h2>) tags with the HtmlTextWriter's RenderBeginTag and RenderEndTag methods:

output.RenderBeginTag("h2");
output.Write(Text);
output.RenderEndTag(  );

The result is that when the text is output, the correct tags are created, as shown in Figure 14-12. (The source output that illustrates the HTML rendered by the HtmlTextWriter is circled and highlighted.)


Figure 14-12. The output and its source

Maintaining state

In the next example, you'll add a button to increase the size of the text. To accomplish this, you'll eschew the rendering support of the HtmlTextWriter, instead writing the text yourself, using a new Size property (to set the size of the output text). The C# code for the Render method should appear as follows:

protected override void Render(HtmlTextWriter output)
{
   output.Write("<font size = " + Size + ">" + Text + "</font>");
}

While the VB.NET code should appear as:

Protected Overrides Sub Render(ByVal output As _
                               System.Web.UI.HtmlTextWriter)
                                  output.Write("<font size = " & Size & ">" & [Text] & "</font>")
End Sub

The Size property must maintain its state through the postback fired by pressing the button. This is as simple as writing to and reading from the ViewState collection maintained by the page (see Chapter 6), as shown in the C# property definition of the Size property:

public int Size
{
   get { return Convert.ToInt32((string) ViewState["Size"]);  }
     set { ViewState["Size"] = value.ToString(  ); }
     }

In VB.NET, the Size property is defined as follows:

Public Property Size(  ) As Integer
   Get
      Return Convert.ToInt32(ViewState("Size"))
   End Get
   Set(ByVal Value As Integer)
      ViewState("Size") = Value.ToString(  )
   End Set
End Property

The property Get method retrieves the value from ViewState, casts it to a string in the case of C#, and then converts that string to its integer equivalent. The property Set method stashes a string representing the size into ViewState.

To ensure that a valid value is in ViewState to start with, you'll also add a constructor to this control. In C#, the constructor is:

public WebCustomControl1(  )
{
   ViewState["Size"] = "1";
   }

In VB.NET, it is:

Public Sub New(  )
   ViewState("Size") = "1"
   End Sub

The constructor initializes the value held in ViewState to 1. Each press of the button will update the Size property. To make this work, you'll add a button declaration in the test page:

<asp:Button 
   Runat="server" 
   Text="Increase Size" 
   OnClick="Button1_Click" 
    id="Button1" />

The important changes here are that you've added an ID attribute (Button1) and defined an event handler for the button. You will also need to create an event handler in the code-behind page.

Be sure to add a reference to the CustomControls DLL file to the web page. That will allow Intellisense to see your object, and you'll be able to declare the control in the code-behind page. In C#, this takes the form:

public class WebForm1 : System.Web.UI.Page
{
   protected System.Web.UI.WebControls.Button Button1;
      protected CustomControls.WebCustomControl1 WC1;

In VB.NET, it takes the form:

Public Class WebForm1
   Inherits System.Web.UI.Page
   
      Protected WithEvents Button1 As System.Web.UI.WebControls.Button
      Protected WC1 As VBCustomControls.WebCustomControl1

You can then use that declaration to set the Size property in the event handler in C# for the button click:

public void Button1_Click(object sender, System.EventArgs e)
{
   WC1.Size += 1;
   }

The VB.NET code is nearly identical:

Public Sub Button1_Click(ByVal sender As Object, _
                   ByVal e As System.EventArgs) Handles Button1.Click
     WC1.Size += 1
End Sub

Example 14-10 is the complete .aspx page for testing, Example 14-11 is the complete C# code-behind page (with the Visual Studio .NET generated code removed to save space), and Example 14-12 is the complete C# source for the custom control. Example 14-13 is the complete VB.NET code-behind page (again, with the Visual Studio .NET-generated code removed to save space), and Example 14-14 provides the complete VB.NET source for the custom control.

Example 14-10: WebForm1.aspx


<%@ Page language="c#" 
Codebehind="WebForm1.aspx.cs" 
AutoEventWireup="false" 
Inherits="CustomControlWebPage.WebForm1" %>

<%@ Register TagPrefix="OReilly" 
Namespace="CustomControls" 
Assembly="CustomControls" %>
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >

<HTML>
  <HEAD>

  </HEAD>
<body MS_POSITIONING="GridLayout">
<form id=Form1 method=post runat="server">
      
      <asp:Button Runat="server" 
      Text="Increase Size" 
      OnClick="Button1_Click" 
      id="Button1" />  

      <OReilly:WebCustomControl1 
      Runat="Server" 
      Text="Hello World!" 
      id="WC1" />
      
</FORM>      
  </body>
</HTML>

Example 14-11: WebForm1.aspx.cs


using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
 
namespace CustomControlWebPage
{
   public class WebForm1 : System.Web.UI.Page
   {
      protected System.Web.UI.WebControls.Button Button1;
      protected CustomControls.WebCustomControl1 WC1;
   
      public WebForm1(  )
      {
         Page.Init += new System.EventHandler(Page_Init);
      }
 
     // ASP.NET generated code elided from listing
 
      private void InitializeComponent(  )
      {    
         this.Button1.Click += new System.EventHandler(this.Button1_Click);
         this.Load += new System.EventHandler(this.Page_Load);
      }
 
      public void Button1_Click(object sender, System.EventArgs e)
      {
         WC1.Size += 1;
      }
   }
}

Example 14-12: WebCustomControl1.cs


using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
 
namespace CustomControls
{
   [DefaultProperty("Text"),
      ToolboxData("<{0}:WebCustomControl1 
      runat=server></{0}:WebCustomControl1>")]
   public class WebCustomControl1 : System.Web.UI.WebControls.WebControl
   {
      private string text;
      
      // constructor initializes the value in ViewState
      public WebCustomControl1(  )
      {
         ViewState["Size"] = "1";
      }
 
      // Created by VS.NET
      [Bindable(true),
         Category("Appearance"),
         DefaultValue("")]
      public string Text
      {
         get {   return text; }
         set{   text = value; }
      }
 
      // Your custom attribute to hold the Size in ViewState
      public int Size
      {
         get { return Convert.ToInt32((string) ViewState["Size"]);  }
         set { ViewState["Size"] = value.ToString(  ); }
      }
 
      // Render method hand renders the size
      protected override void Render(HtmlTextWriter output)
      {
         output.Write("<font size = " + Size + ">" + 
                  Text + "</font>");
      }
   }
}

Example 14-13: WebForm1.aspx.vb


Imports CustomControls.WebCustomControl1
 
Public Class WebForm1
    Inherits System.Web.UI.Page
 
   Protected WithEvents Button1 As System.Web.UI.WebControls.Button
   Protected WC1 As VBCustomControls.WebCustomControl1
 
   Public Sub Button1_Click(ByVal sender As Object, _
                            ByVal e As System.EventArgs) _
                            Handles Button1.Click
      WC1.Size += 1
   End Sub
End Class

Example 14-14: WebCustomControl1.vb


Imports System.ComponentModel
Imports System.Web.UI
Imports System.Drawing
 
<DefaultProperty("Text"), ToolboxData("<{0}:WebCustomControl1 _
runat=server></{0}:WebCustomControl1>")> _
Public Class WebCustomControl1
   Inherits System.Web.UI.WebControls.WebControl
 
   Dim _text As String
 
   Public Sub WebCustomControl1(  )
      ViewState("Size") = "1"
   End Sub
 
    <Bindable(True), Category("Appearance"), DefaultValue("")> _
    Property [Text](  ) As String
        Get
            Return _text
        End Get
 
        Set(ByVal Value As String)
            _text = Value
        End Set
    End Property
 
    Protected Overrides Sub Render( _
                        ByVal output As System.Web.UI.HtmlTextWriter)
      output.Write("<font size = " & Size & ">" & [Text] & "</font>")
    End Sub
 
   Public Property Size(  ) As Integer
      Get
         Return Convert.ToInt32(ViewState("Size"))
      End Get
      Set(ByVal Value As Integer)
         ViewState("Size") = Value.ToString(  )
      End Set
   End Property
 
End Class

To illustrate the effect of clicking the button, in Figure 14-13 I created two instances of the program, and in the second instance I pressed the button three times.


Figure 14-13. Maintaining state

Each time the button is clicked, the state variable Size is incremented; when the page is drawn, the state variable is retrieved and used to set the size of the text.

Pages: 1, 2, 3, 4, 5

Next Pagearrow