WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

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

@Control Properties

There can be only one @Control directive for each user control. This attribute is used by the ASP.NET page parser and compiler to set attributes for your user control. Possible values are shown in Table 14-1.

Table 14-1: Values for @Control properties

Attribute

Description

Possible values

AutoEventWireup

true (the default) indicates the page automatically posts back to the server. If false, the developer must fire the server event manually.

true or false; default is true.

ClassName

The class name for the page.

Any valid class name.

CompilerOptions

Passed to compiler.

Any valid compiler string indicating options.

Debug

Whether to compile with debug symbols.

true or false; default is false.

Description

Text description of the page.

Any valid text.

EnableViewState

Is view state maintained for the user control?

true or false; default is true.

Explicit

Should page be compiled with VB.NET option explicit

true or false; default is false.

Inherits

Defines a code-behind class.

Any class derived from UserControl.

Language

The language used for inline rendering and server-side script blocks.

Any .NET-supported language.

Strict

Page should be compiled using VB.NET Strict option?

true or false; default is false.

Src

Name of the source file for the code-behind.

Any valid filename.

WarningLevel

Compiler warning level at which compilation will abort.

0-4.

Figure 14-4. Loading the book list from the database in a user control

 

TIP:   The src attribute is not used in Visual Studio .NET. VS.NET uses precompiled code-behind classes with the Inherits attribute.

Adding Properties

You can make your user control far more powerful by adding properties. Properties allow your client (in this case WebForm1) to interact with your control, setting attributes either declaratively (when the user control is added to the form) or programmatically (while the program is running).

You can, for example, give your book list control properties for the server name, the password, and the database to which you will connect. You do this in four steps:

  1. Create a property. You must decide if you will provide a read-write, read-only, or write-only property. For this example, you'll provide read-write properties.
  2. Provide an underlying value for the property. You can do this by computing the property, retrieving it from a database or, as you'll do here, storing the underlying value in a private member variable. You must also decide if you'll provide a default value for your properties.
  3. Integrate the underlying values into the body of the code.
  4. Set the property from the client, either declaratively (as an attribute) or programmatically.

Creating a property

There is nothing special about the property for the user control; you create it as you would any property for a class. In C#, this takes the form:

public string ServerName
{
   get
   {
      return serverName;
   }
   set
   {
      serverName = value;
   }
}
public string Password 
{ 
      get { return password; } set { password = value; } 
} 
 
public string DB 
{ 
   get { return db; } set { db = value; } 
} 

In VB.NET, the code is:

Public Property ServerName As String
   Get
      Return sServerName
   End Get
   Set
      sServerName = Value
   End Set
End Property
 
Public Property Password As String
   Get
      Return sPassword
   End Get
   Set
      sPassword = Value
   End Set
End Property
 
Public Property DB As String 
   Get 
      Return sDB
   End Get
   Set
      sDB = Value
   End Set
End Property

Note that you can take advantage of C#'s case-sensitivity to differentiate the property name (such as ServerName) from the private variable representing the underlying property value (such as serverName). However, because VB.NET is case-insensitive, you must use a property name (such as ServerName) that is clearly distinctive from the private variable holding the underlying property value (such as sServerName).

When coding in C#, we tend to prefer the more extended property declaration style, as shown with ServerName. However, in this book we often use the terser form to save space, as shown for Password and DB.

Providing an underlying value for the property

You certainly can compute the value of a property, or look up the value in a database. In this example, however, you'll simply create member variables to hold the underlying value. In C#, the code is:

private string serverName;
private string password;
private string db = "ProgASPDotNetBugs";

In VB.NET, it's:

Private sServerName, sPassword As String
Private sDB As String = "ProgASPDotNegBugs"

Acting in the role of control designer, you have decided to provide a default value for the db property (the name of the database), but you have not provided a default value for the name of the server or the sa (system administrator) password. This is appropriate; you can safely assume the database is ProgASPDotNetBugs, but you can't possibly know in advance what database server will be used, or what the sa password is.

Integrating the property into your code

Having declared the properties, you must now modify the connection string to use the properties, rather than the hard-coded values. In C#, the code is:

string connectionString = 
   "server= " + serverName + 
   "; uid=sa;pwd=" +
   password + "; database= " + db;

and in VB.NET, it's:

Dim connectionString As String = _
   "server= " & sServerName & _
   "; uid=sa;pwd=" & _
   sPassword & "; database= " & sDB

Here you concatenate hard-coded string values ("server=") with the member variables that will be set through the properties. You could, as an alternative, just use the properties' Get accessors, rather than using the underlying values:

string connectionString = 
   "server= " + ServerName + 
   "; uid=sa;pwd=" +
   Password + "; database= " + DB;

While using the underlying value is trivially more efficient, using the property has the advantage of allowing you to change the implementation of the property without breaking this code.

Setting the property from the client

In the client you must now provide values for the two required attributes, ServerName and Password, and you may provide a value for the DB property. For example, you might write:

<OReilly:bookList runat="server" ID="Booklist"
DB="ProgASPDotNetBugs" Password="yourPassWord"
ServerName="YourServer"

Notice that in the preceding code, you have provided a value for the DB property. This code will continue to work if you leave out this attribute, but adding it makes the code self-documenting.

Handling Events

Event handling with user controls can be a bit confusing. Within a user control (e.g., bookList), you may have other controls (e.g., a list box). If those internal controls fire events, you'll need to handle them within the user control itself. The page the user control is placed in will never see those events.

That said, a user control itself can raise events. You may raise an event in response to events raised by internal controls, in response to user actions or system activity, or for any reason you choose.

Handling events in C#

You declare new events for the user control just as you would for any class. Example 14-6 shows the complete code listing for BookList.ascx.cs.

Example 14-6: BookList.ascx.cs

namespace UserControl2A1
{
   using System;
   using System.Data;
   using System.Data.SqlClient;
   using System.Drawing;
   using System.Web;
   using System.Web.UI.WebControls;
   using System.Web.UI.HtmlControls;
 
   public abstract class BookList : System.Web.UI.UserControl
   {
      protected System.Web.UI.WebControls.DropDownList ddlBooks;
      private string serverName;
      private string password = "oWenmEany";
      private string db = "ProgASPDotNetBugs";
 
      public delegate void 
         ListChangedHandler(object sender, EventArgs e);
      public event ListChangedHandler ListChanged;
 
      protected virtual void OnListChanged(EventArgs e)
      {
         if (ListChanged != null)
            ListChanged(this, e);
      }
 
      public string ServerName
      {
         get
         {
            return serverName;
         }
         set
         {
            serverName = value;
         }
      }
      public string Password 
      { 
         get { return password; } 
         set { password = value; } 
      } 
 
      public string DB 
      { 
         get { return db; } 
         set { db = value; } 
      } 
      
      public BookList(  )
      {
         this.Init += new System.EventHandler(Page_Init);
      }
 
      private void Page_Load(object sender, System.EventArgs e)
      {
         if (!IsPostBack)
         {
            string connectionString = 
               "server= " + ServerName + 
               "; uid=sa;pwd=" +
               Password + "; database= " + DB;
 
            // get records from the Bugs table
            string commandString = 
               "Select BookName from Books";
 
            // create the data set command object 
            // and the DataSet
            SqlDataAdapter dataAdapter = 
               new SqlDataAdapter(
               commandString, connectionString);
 
            DataSet dataSet = new DataSet(  );
 
            // fill the data set object
            dataAdapter.Fill(dataSet,"Bugs");
 
            // Get the one table from the DataSet
            DataTable dataTable = dataSet.Tables[0];
 
            ddlBooks.DataSource = dataTable.DefaultView;
            ddlBooks.DataTextField = "BookName";
            ddlBooks.DataBind(  );
         }
   
      }
 
      private void Page_Init(object sender, EventArgs e)
      {
         InitializeComponent(  );
      }
 
        #region Web Form Designer generated code
      ///        Required method for Designer support - do not modify
      ///        the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent(  )
      {
         this.ddlBooks.SelectedIndexChanged += 
            new System.EventHandler(this.OnSelectedIndexChanged);
         this.Load += new System.EventHandler(this.Page_Load);
 
      }
        #endregion
 
      public class BookListArgs : EventArgs
      {
         public string bookSelected;
      }
 
      private void OnSelectedIndexChanged(
         object sender, System.EventArgs e)
      {
         OnListChanged(e);
      }
   }
}

You start by declaring a delegate that describes the event procedure:

public delegate void ListChangedHandler(object sender, EventArgs e);

You then declare the event itself:

public event ListChangedHandler ListChanged;

You must create a method that begins with the letters "On" followed by the name of the event, as follows:

protected virtual void OnListChanged(EventArgs e)
{
}

This method typically checks that the event has one or more handlers registered, and if so, it raises the event, as the following code shows:

protected virtual void OnListChanged(EventArgs e)
{
   if (ListChanged != null)
      ListChanged(this, e);
}

You are now ready to test the event. For this example, go back to the list box within the book list user control and add an event handler for the selected item being changed:

private void OnSelectedIndexChanged (object sender, System.EventArgs e)
{
   OnListChanged(e);
}

When the item is changed, you call the OnListChanged method, which in turn fires the ListChanged event. More about this shortly.

Your web page can add an event handler for its BookList element. The declaration in the .aspx page is unchanged:

<td><OREILLY:BOOKLIST id=Booklist runat="server" 
    ServerName="yourServer" Password="yourPW" 
    DB="ProgASPDotNetBugs"></OReilly:bookList></TD></TR>

The code-behind changes, however. To register the event, you'll need an instance of a booklist object:

protected UserControl3.BookList Booklist;

You now have only to register the event handler. Within the InitializeComponent method of WebForm1.aspx.cs, add this code:

this.Booklist.ListChanged += 
new UserControl3.BookList.ListChangedHandler(this.Booklist_ListChanged);

The event handler Booklist_ListChanged is thus wired to the ListChanged event of the booklist. When the user chooses a book, the internal list box fires a postback event, the OnSelectedIndexChanged event fires within the .ascx page, and the OnSelectedIndexChanged event handler within the user control responds.

When the ListChanged event is fired, it is caught in the containing page's BookList_ListChanged method, and the label is updated:

public void Booklist_ListChanged(object sender, System.EventArgs e)
{
   lblMsg.Text = "The list changed!!";
}

To the user, it appears just as it should; the list box within the user control appears just to be another control with which the user can interact, as shown in Figure 14-5.

Figure 14-5. The List event fired

 

Pages: 1, 2, 3, 4

Next Pagearrow