Section 14.1. User Controls

14.1. User Controls

User controls allow you to save a part of an existing ASP.NET page and reuse it in many other ASP.NET pages. A user control is almost identical to a normal .aspx page, with the following differences:

  • User controls have an .ascx extension rather than an .aspx extension.

  • User controls may not have <html> , <body> , or <form> tags.

  • User controls have a Control directive rather than a Page directive.

The simplest user control is one that displays only HTML. A classic example of a simple user control is an HTML page that displays a copyright notice.

User controls were originally called pagelets , which we think is more descriptive; alas, Microsoft has elected to call them User Controls and so shall we. When you see the term user control , think this: a bit of a content page that can be reused in other content pages .


VS2005 provides support for creating user controls. To see this at work, you'll create a new web site named UserControls. Right-click on the web site folder in the Solution Explorer and choose Add New Item to bring up the Add New Item dialog box. One of the choices is Web User Control. Select this and give it the name Copyright.ascx .

This choice opens the new file in Source view. Initially, the file contains only a Control directive:

 <%@ Control Language="C#" AutoEventWireup="true"        CodeFile="Copyright.ascx.cs" Inherits="Copyright" %> 

This directive, similar to the Page directive described in Chapter 6, sets the language, the name of the code-behind file, and the class, and so on.

Copy the following code into the new .ascx file below the Control directive:

 <table>        <tr>           <td align="center">Copyright 2005 Liberty Associates, Inc.</td>        </tr>        <tr>           <td align="center">Support at http://www.LibertyAssociates.com</td>        </tr>     </table> 

You can now add this user control to any number of pages. You'll begin by returning to Default.aspx and adding a couple web controls to the page. Drag a Label control onto the page and set its Text property to Hello . Drag a Button control onto the page and set its Text property to Change . Double-click on the button in Design view to go to its default event handler and enter the following line of code:

 Label1.Text = "Changed!"; 

Default.aspx now has a label and a button, but we want to add the copyright. You can reuse the copyright user control by adding two lines to default.aspx : the register directive for the user control and an instance of the user control itself.

Switch to source view and, at the top of default.aspx file, add the following Register directive immediately after the Page directive:

 <%@Register tagprefix="OReilly" Tagname="copyright" src="copyright.ascx" %> 

The tagprefix for the Label control is asp and its Tagname is Label . Your registration statement establishes your tagprefix ( OReilly ) and the Tagname of your user control ( copyright ).

The tilde character (~) is interpreted by ASP.NET as indicating the path to the root of you web application as in:

 ~/myUserControls/mypage.ascx 


You can add an instance of your user control like any other control. The complete source for the content file for UserControls is shown in Example 14-1.

Example 14-1. Default.aspx for UserControls
 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"      Inherits="_Default" %>  <%@Register tagprefix="OReilly" Tagname="copyright"    src="copyright.ascx" %>  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>User Controls</title> </head> <body>     <form id="form1" runat="server">     <div>         <asp:Label ID="Label1" runat="server" Text="Hello"></asp:Label>         <asp:Button ID="Button1" runat="server"           OnClick="Button1_Click" Text="Change" />       </div>     </form>  <OReilly:copyright ID="Copyright1" runat="server" />  </body> </html> 

Run the program and the copyright user control is displayed as if you had put its HTML into the content file, as shown in Figure 14-1.

The user control can be reused in any .aspx page. If you update the copyright, you will make that update only in the one .ascx file, and it will be displayed appropriately in all the pages that use that control.

Figure 14-1. Copyright user control

14.1.1. User Controls with Code

User controls can have events and other code associated with them to make for more sophisticated reusable code. Suppose, for example, that you'd like to reuse the customer data list that you developed in Chapter 9 in the application WebNorthWindDataControls.

To convert this .aspx page and its code behind into a re-usable user control you will need to:

  1. Create a user control skeleton in your new project.

  2. Excise the reusable code from the .aspx and paste it into your new control.

  3. Bring over the support code from the code-behind to the user control.

  4. Bring over the appropriate connection string from web.config.

Begin by adding a new user control called CustomerDataList.ascx to the ongoing example. Open WebNorthWindDataControls in a separate instance of Visual Studio and pick out the entire default.aspx code from the opening to the closing <div> tags. Drop what you've copied into the new user control, CustomerDataList .

To make the control appear more natural in your page, change the first line of HTML from this:

 <h1>DataList Demo</h1> 

to this:

 <h2>Customers</h2> 

Open the code-behind for your new user control and copy over the implemented methods from Default.aspx.cs .

In the content file of the user control, you have a pair of SqlDataSource controls, each of which has the following connection string element:

 ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 

To support that, copy the following lines from the WebNorthWindDataControl project's web.config file:

 <connectionStrings>           <add name="NorthwindConnectionString"              connectionString="Data Source=Mozart;              Initial Catalog=Northwind;              Persist Security Info=True;              User ID=<your user>;              Password=<your password>"              providerName="System.Data.SqlClient"/>        </connectionStrings> 

Paste that connection string element over the empty connection string element in the web.config of the UserControls project and rebuild the web site.

Your control is now ready to use. Add it to default.aspx in the UserControls web site in two steps. First, register it by adding a Register directive:

 <%@Register        tagprefix="OReilly"        Tagname="customerDL"        src="CustomerDataList.ascx" %> 

Second, place an instance of the control under the button as in the highlighted line in the following code snippet:

 <asp:Button ID="Button1" runat="server"       OnClick="Button1_Click" Text="Change" />  <OReilly:customerDL ID="custDL1" runat="server" />  

The complete content file for UserControls after adding the customer DataList user control is listed in Example 14-2 with the additions highlighted.

Example 14-2. UserControls after adding Customer DataList user control
 <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs    " Inherits="_Default" %> <%@Register tagprefix="OReilly" Tagname="copyright" src="copyright.ascx" %>  <%@Register tagprefix="OReilly"    Tagname="customerDL"    src="CustomerDataList.ascx" %>  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">     <title>User Controls</title> </head> <body>     <form id="form1" runat="server">     <div>       <h1>User Controls</h1>        <asp:Label ID="Label1" runat="server" Text="Hello"></asp:Label>        <asp:Button ID="Button1" runat="server" Text="Change"                    OnClick="Button1_Click" />  <OReilly:customerDL ID="custDL1" runat=server />  </div>     </form>     <OReilly:copyright ID="Copyright1" runat="server" /> </body> </html> 

When you run the UserControls web site, default.aspx comes up with the complete and populated DataList in place as you would expect, as shown in Figure 14-2.

Figure 14-2. DataList user control

Clicking on the Edit button puts the record into Edit Mode as it did before you turned your page into a reusable data control, as shown in Figure 14-3.

Figure 14-3. DataList user control in Edit Mode

14.1.2. @Control Directive

There can be only one @Control directive for each user control. This directive 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

Indicates if view state is maintained for the user control.

TRue or false ; default is TRue .

Explicit

Indicates whether the page should 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.

Src

Name of the source file for the code-behind.

Any valid filename.

Strict

Indicates if the page should be compiled using VB.NET Strict option.

true or false ; default is false .

WarningLevel

Compiler warning level at which compilation will abort.

- 4


14.1.3. Properties

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

To get started, copy the example web site UserControls to a new web site called UserControlsProperties.

You can, for example, give your CustomerDataList control properties for the number of columns to render and if to lay them out vertically or horizontally. You do this in four steps:

  1. Create properties in the control. 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 decide if you'll provide a default value for your properties.

  3. Integrate the underlying values into the body of the code; you'll do that, in this case, by setting these values in the PreRender event of the control.

  4. Set the property from the client declaratively (as an attribute) or programmatically. In this case, you'll set them programmatically in response to user input.

14.1.3.1. 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. To do this, add the following code to the CustomerDataList class in CustomerDataList.ascx.cs :

 public int HowManyColumns     {         get { return howManyColumns; }         set { howManyColumns = value; }     }     public RepeatDirection WhichDirection     {         get { return whichDirection; }         set { whichDirection = value; }     } 

14.1.3.2. Providing an underlying value for the property

You can compute the value of a property or look up the value in a database. In this example, you'll create member variables to hold the underlying value. Add these two lines of code to CustomerDataList.ascx.cs :

 private int howManyColumns = 3;     private RepeatDirection whichDirection = RepeatDirection.Horizontal; 

RepeatDirection is an enumerated constant provided by the framework. Intellisense will offer the valid choices when you type the dot following RepeatDirection .

14.1.3.3. Integrating the property into your code

Having declared the properties, you must modify the code so these values are used when creating the control. You can't do this in the Page_Load of the user control code-behind file because the event handler for setting the properties runs after Page_Load . You want to use the new property values before you render the control, so put the following code in the code-behind file to handle the PreRender event:

 protected void Page_PreRender(object sender, EventArgs e)     {         this.DataList1.RepeatColumns = this.howManyColumns;         this.DataList1.RepeatDirection = this.whichDirection;     } 

14.1.3.4. Setting the property from the client

You'll modify the client to lay out the controls within a table as a convenience. While you are at it, you'll add a text box for the number of columns and a drop-down to allow the user to decide vertical versus horizontal. Finally, you'll add a button which will repost the page so the new values are put into place. The complete content file for UserControlsProperties , default.aspx , is shown in Example 14-3. A Table control has been used to control the layout. The relevant changes (other than that Table control) are highlighted.

Example 14-3. Default.aspx for UserControlsProperties
 <%@ Page Language="C#"    AutoEventWireup="true"    CodeFile="Default.aspx.cs"    Inherits="_Default" %> <%@Register    tagprefix="OReilly"    Tagname="copyright"    src="copyright.ascx" %> <%@Register    tagprefix="OReilly"    Tagname="customerDL"    src="CustomerDataList.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server">    <title>User Controls</title> </head> <body>    <form id="form1" runat="server">    <div>       <asp:Table ID="table1" runat="server">         <asp:TableRow>            <asp:TableCell ColumnSpan="3">               <asp:Label ID="Label1" runat="server" Text="Hello" /> &nbsp;               <asp:Button ID="Button1" runat="server"               OnClick="Button1_Click" Text="Change" />            </asp:TableCell>         </asp:TableRow>         <asp:TableRow>            <asp:TableCell>  <asp:Label ID="Label2" runat="server" Text="Columns" />  &nbsp;  <asp:TextBox ID="txtNumberColumns" runat="server"                            width="25"/>  </asp:TableCell>             <asp:TableCell>               <asp:Label ID="Label3" runat="server" Text="Direction" />                &nbsp;  <asp:DropDownList ID="ddlDirection" runat="server" >                    <asp:ListItem Value="H">Horizontal</asp:ListItem>                    <asp:ListItem Value="V">Vertical</asp:ListItem>                 </asp:DropDownList>  </asp:TableCell>            <asp:TableCell>  <asp:Button ID="btnSetProperties" runat="server"                           Text="Set Properties"                           OnClick="btnSetProperties_OnClick" />  </asp:TableCell>         </asp:TableRow>         <asp:TableRow>            <asp:TableCell ColumnSpan="3">               <OReilly:customerDL ID="custDL1" runat="server" />            </asp:TableCell>         </asp:TableRow>       </asp:Table>     </div>    </form>    <OReilly:copyright ID="Copyright1" runat="server" /> </body> </html> 

The Click event handler for the Set Properties button will examine the drop-down and set the DataList control's RepeatDirection property accordingly . It will examine txtNumberColumns and set the HowManyColumns property of the user control from that value. Once these are set, the control will know how to render itself. The Click event handler for btnSetProperties has been declared in Example 14-3 to be btnSetProperties_OnClick , so add the code from Example 14-4 to the code-behind file for the page, default.aspx.cs :

Example 14-4. btnSetProperties Click event handler for UserControlsProperties
 protected void btnSetProperties_OnClick(object sender, EventArgs e) {     if (ddlDirection.SelectedValue == "H")     {         this.custDL1.WhichDirection = RepeatDirection.Horizontal;     }     else     {         this.custDL1.WhichDirection = RepeatDirection.Vertical;     }     if (this.txtNumberColumns.Text.Length > 0)     {         this.custDL1.HowManyColumns =            Convert.ToInt32(this.txtNumberColumns.Text);     } } 

When you run the application, the page is displayed using the default values.

To simplify the code we are not using validators to ensure, for example, that the text in txtNumberColumns is actually a numeric value. For more on validators, please see Chapter 8.


If you set new values and then click Set Properties, the new values will be placed into the control's properties and used when the control is rendered, as shown in Figure 14-4.

Figure 14-4. Setting the data control properties

14.1.4. Handling Events

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

That said, a user control can raise its own 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.

Your user control can publish any event it chooses, and your consuming application (in this case default.aspx ) may respond to those events if it chooses. Here are the steps:

  1. The user control defines a delegate for the event.

  2. The user control defines the event.

  3. The user control defines a method that raises the event if anyone has registered to receive the event.

  4. The user control calls that method from the place in the code where the event should be raised.

  5. If the user control needs to pass along additional information for an event, the user control will define a class that derives from EventArgs , adds a parameter of that class to the delegate definition, and create an instance of that EventArgs -derived class when raising the event.

  6. The consuming class registers for the event, indicating which method should be called if the event is raised.

  7. The consuming class's event handler handles the event in whatever way is appropriate.

To demonstrate how this is all accomplished, copy the current example to a new web site, called UserControlsEvents. In this example, the CustomerDataList control will declare two events. The first, EditRecord , will be raised when a record is being edited, and will pass along, in ChangedRecordEventArgs (derived from EventArgs ), the name of the company. The second event, FinishedEditRecord , will be raised when the user either saves the update or cancels the update.

You declare new events for the user control as you would for any class. In this case, you'll declare two delegates and two events for the CustomerDataList in the code-behind of the user control:

 public delegate void EditRecordHandler(         object sender, ChangedRecordEventArgs e);     public event EditRecordHandler EditRecord;     public delegate void FinishedEditRecordHandler(         object sender, EventArgs e);     public event FinishedEditRecordHandler FinishedEditRecord; 

The first delegate has, as its second argument, a ChangedRecordEventArgs object. This is a class defined within the definition of the CustomerDataList class, specifically to pass along the company name that is being edited:

 public class ChangedRecordEventArgs : EventArgs     {         private string companyName;         public string CompanyName         {             get { return companyName; }         }         public ChangedRecordEventArgs(string companyName)         {             this.companyName = companyName;         }     } 

The company name is set in the constructor, and there is a read-only property for the event handler to read the name of the company that is being edited.

In addition to declaring the two events, you must declare methods in the CustomerDataList class that fire the events if anyone has registered to receive them:

 protected virtual void OnEditRecord(ChangedRecordEventArgs e)     {         if (EditRecord != null)         {             EditRecord(this, e);         }     }     protected virtual void OnFinishedEditRecord(EventArgs e)     {         if (FinishedEditRecord != null)         {             FinishedEditRecord(this, e);         }     } 

Finally, you must add calls to these methods to the places in your code where you want the events to be raised. The first place is when the user clicks the Edit button. An event handler exists for the EditCommand event of the DataList control. Add the highlighted lines from the following snippet to add these calls:

 protected void DataList1_EditCommand(object source,                                          DataListCommandEventArgs e)     {         DataList1.EditItemIndex = e.Item.ItemIndex;         DataBind(  );  Label lbl = (Label) e.Item.FindControl("CompanyNameLabel");         string companyName = lbl.Text;         ChangedRecordEventArgs cre = new ChangedRecordEventArgs(companyName);         OnEditRecord(cre);  } 

The first two lines are unchanged. The next two lines extract the company name from the Company Name Label within the selected DataList item. The next line creates an instance of your new ChangedRecordEventArgs class, and the final line calls the method that will raise the event.

You'll want to modify the pre-existing UpdateCommand and CancelCommand event handlers to raise the OnFinishedEditRecord . Add the highlighted line from the following snippet to both of those event handlers:

 protected void DataList1_CancelCommand(object source,                                            DataListCommandEventArgs e)     {         DataList1.EditItemIndex = -1;         DataBind(  );  OnFinishedEditRecord(new EventArgs(  ));  } 

There is no data to pass in, so instead pass in a new instance of the placeholder class EventArgs to follow the convention that every event has an EventArgs argument.

The client of your control ( default.aspx ) must register to receive these events. It will do so in its Page_Load method:

 protected void Page_Load(object sender, EventArgs e)     {         this.custDL1.EditRecord +=             new CustomerDataList.EditRecordHandler(custDL1_EditRecord);         this.custDL1.FinishedEditRecord +=             new CustomerDataList.FinishedEditRecordHandler(               custDL1_FinishedEditRecord);     } 

The first line registers that you want to receive the EditRecord event and indicates that the method to call is custDL1_EditRecord . The second line registers that you want to receive the FinishedEditRecord event and indicates that the method to call is custDL1_FinishedEditRecord .

These two methods add or remove text to a new label added to the user interface of default.aspx . Add the highlighted code from this snippet inside the Table control:

 <asp:Table ID="table1" runat="server">       <asp:TableRow>          <asp:TableCell >             <asp:Label ID="Label1" runat="server" Text="Hello" /> &nbsp;             <asp:Button ID="Button1" runat="server"             OnClick="Button1_Click" Text="Change" />          </asp:TableCell>  <asp:TableCell ColumnSpan="2">               <asp:Label ID="lblDisplayCompany" runat="server" Text="" />          </asp:TableCell>       </asp:TableRow>  

Add the next two code snippets to the code-behind of the page, default.aspx.cs . The first method sets the text of this new label to the name of the company:

 protected void custDL1_EditRecord(         object sender,         CustomerDataList.ChangedRecordEventArgs e)     {  lblDisplayCompany.Text = "Editing " + e.CompanyName;  } 

The second event handler sets the label back to an empty string (making it invisible):

 protected void custDL1_FinishedEditRecord(object sender, EventArgs e)     {         lblDisplayCompany.Text = string.Empty;     } 

The result is that when you are editing a record, the name of the record you are editing is displayed by default.aspx , as shown in Figure 14-5. The complete listings for the two code-behind files in this example, with changes highlighted, are shown in Examples 14-5 and 14-6. There are no changes to the content file for the user control since the previous example and the single addition to the content file for the consuming page, so neither of those files are listed here.

Figure 14-5. Editing record EventHandled

Example 14-5. CustomDataList.ascx.cs for UserControlsEvents
 using System; using System.Data; using System.Configuration; using System.Collections; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class CustomerDataList : System.Web.UI.UserControl {  public delegate void EditRecordHandler(object sender, ChangedRecordEventArgs e);    public event EditRecordHandler EditRecord;    public delegate void FinishedEditRecordHandler(object sender, EventArgs e);    public event FinishedEditRecordHandler FinishedEditRecord;  private int howManyColumns = 3;    private RepeatDirection whichDirection = RepeatDirection.Horizontal;    public int HowManyColumns    {       get { return howManyColumns; }       set { howManyColumns = value; }    }    public RepeatDirection WhichDirection    {       get { return whichDirection; }       set { whichDirection = value; }    }    protected void Page_Load(object sender, EventArgs e)     {     }     protected void Page_PreRender(object sender, EventArgs e)     {        this.DataList1.RepeatColumns = this.howManyColumns;        this.DataList1.RepeatDirection = this.whichDirection;     }    protected void DataList1_EditCommand(object source,                                         DataListCommandEventArgs e)     {        DataList1.EditItemIndex = e.Item.ItemIndex;        DataBind(  );  Label lbl = (Label)e.Item.FindControl("CompanyNameLabel");        string companyName = lbl.Text;        ChangedRecordEventArgs cre =           new ChangedRecordEventArgs(companyName);        OnEditRecord(cre);  }    protected void DataList1_CancelCommand(object source,                                           DataListCommandEventArgs e)     {        DataList1.EditItemIndex = -1;        DataBind(  );  OnFinishedEditRecord(new EventArgs(  ));  }     protected void DataList1_UpdateCommand(object source,                                            DataListCommandEventArgs e)     {  OnFinishedEditRecord(new EventArgs(  ));  }     protected void DataList1_DeleteCommand(object source,                                            DataListCommandEventArgs e)     {        // (1) Get the recordID from the selected item (a string)        string recordID =             (DataList1.DataKeys[e.Item.ItemIndex]).ToString(  );        // (2) Get a reference to the customerID parameter        System.Web.UI.WebControls.Parameter param =           DataListCustomerDeleteDataSource.DeleteParameters["CustomerID"];        // (3) Set the parameter's default value to the value for        // the record to delete        param.DefaultValue = recordID;        // (4) Delete the record        DataListCustomerDeleteDataSource.Delete(  );        // (5) Rebind the list        DataBind(  );     }  public class ChangedRecordEventArgs : EventArgs    {       private string companyName;       public string CompanyName       {          get { return companyName; }       }       public ChangedRecordEventArgs(string companyName)       {          this.companyName = companyName;       }    }    protected virtual void OnEditRecord(ChangedRecordEventArgs e)    {       if (EditRecord != null)       {          EditRecord(this, e);       }    }    protected virtual void OnFinishedEditRecord(EventArgs e)    {       if (FinishedEditRecord != null)       {          FinishedEditRecord(this, e);       }    }  } 

Example 14-6. default.aspx.cs for UserControlsEvents
 using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; public partial class _Default : System.Web.UI.Page {     protected void Page_Load(object sender, EventArgs e)     {        this.custDL1.EditRecord +=            new CustomerDataList.EditRecordHandler(custDL1_EditRecord);        this.custDL1.FinishedEditRecord +=            new CustomerDataList.FinishedEditRecordHandler(              custDL1_FinishedEditRecord);     }    protected void Button1_Click(object sender, EventArgs e)    {       Label1.Text = "Changed!";    }    protected void btnSetProperties_OnClick(object sender, EventArgs e)    {       if (ddlDirection.SelectedValue == "H")       {          this.custDL1.WhichDirection = RepeatDirection.Horizontal;       }       else       {          this.custDL1.WhichDirection = RepeatDirection.Vertical;       }       if (this.txtNumberColumns.Text.Length > 0)       {          this.custDL1.HowManyColumns =             Convert.ToInt32(this.txtNumberColumns.Text);       }    }  protected void custDL1_EditRecord(object sender,                            CustomerDataList.ChangedRecordEventArgs e)    {       lblDisplayCompany.Text = "Editing " + e.CompanyName;    }    protected void custDL1_FinishedEditRecord(object sender, EventArgs e)    {       lblDisplayCompany.Text = string.Empty;    }  } 



Programming ASP. NET
Programming ASP.NET 3.5
ISBN: 0596529562
EAN: 2147483647
Year: 2003
Pages: 173

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net