asp:Feature

LANGUAGES: C# | VB.NET

ASP.NET VERSIONS: 2.0

 

Customize the Grid

Tailor Your Next Project

 

By Oscar Peli

 

At the end of last year, my chief asked me to build a data management application to manage some tabular data. I did it in a couple of days using the GridView control. When I submitted the application to my chief, he noticed two problems. First he noticed that the GridView default command link captions (Delete, Cancel, etc.) were very equivocal. This is really true here in Italy because we say Cancella for Delete and Annulla for Cancel ... so Cancella and Cancel can be misunderstood very easily.

Also, he noticed that a delete command without any kind of confirmation message was not good. These remarks were the starting point of my control extension work. In this article I want to show you what I ve done; you ll see how to customize GridView command link captions and how to add a confirmation dialog box to the GridView delete command.

 

Properties & Overrides

To get you started, I want to outline some guidelines you must follow when you want to extend base controls by which I mean adding some advanced capabilities that the base control doesn t provide. For data management controls like GridView or DetailsView, and relative bound controls, you may want to change the command link captions (as you ll see in this article) or you may want to add the ability to configure your GridView via XML at run time. If you think about bound fields you may want to add some validation capabilities to your controls, or maybe you want to build new kinds of bound controls from scratch.

 

As you ll see, you can summarize the process of building new controls in the Properties & Overrides paradigm. When extending an existing control to build a special purpose one, you must implement special behaviors that the base control doesn t provide. To describe these behaviors you normally need to define new control properties. For example, you might need to add an EditLinkButtonText property to carry the custom link command caption for the GridView Edit command or add an XmlConfigFileUrl property to carry the location of the XML document that you ll use to configure the GridView at run time. Another example would be to use a RegularExpressionValidationString property to carry the regular expression you ll use to check a bound control user input.

 

Once you ve defined the control behaviors you have to implement them. To do so you must override lifecycle methods that represent the control building stages from the request to the response. If you want to extend a databound control like GridView you must override methods like OnRowCreated, which handles the RowCreated event and is called every time a row in the GridView control is created. (This allows you to provide code that performs a custom routine, such as adding custom content to a row or overriding base properties.)

 

If you want to extend BoundField controls you must override the InitializeCell method that, as you can read in the MSDN Library, is implemented by BoundField-derived types to add text and controls to a TableCell object of a data control that uses tables to display a user interface. These data controls create the complete table structure row-by-row when the control s CreateChildControls method is called. The InitializeCell method is called by the InitializeRow method of data controls, such as DetailsView and GridView. So, to extend validation-enabled BoundFields, you must add in method validation controls bound to the TextBox created by the base method (I ll address the implementation of such a control in a future article).

 

If you want to build a new kind of control, you must override the ExtractValuesFromCell method that is implemented by types derived from DataControlField to associate the current field with a value, if applicable. The field/value pair is stored in the dictionary collection that is passed to the method, which is called by the ExtractRowValues method of data controls such as DetailsView and GridView. In other words, this method allows the binding container controls, like GridView or DetailsView, to retrieve input values when the control is in edit or insert mode.

 

The last method override I want to talk about is OnDataBindField, which is a helper method used to bind the value of a field in the data source to a corresponding cell in the BoundField object. This lets you represent data in a custom way, such as showing a custom image derived from the value of the corresponding field.

 

This is only a small list of what you can override; surfing the MSDN Library can give you some ideas of where to implement your custom control behaviors. In this article you ll see an example of GridView customization.

 

The PoweredGridView Class

Let s say you need to implement a GridView control that displays custom link command captions and shows a confirmation dialog box when you try to delete a data row. The first thing you need to do is create a class that inherits from the GridView class (see Figure 1).

 

C#

using System;

using System.ComponentModel;

using System.Web.UI.WebControls;

namespace Powered03Cs

{

 public class PoweredGridView : GridView

 {

...

 }

}

 

VB.NET

Imports System.Web.UI.WebControls

Public Class PoweredGridView

   Inherits GridView

...

End Class

Figure 1: Create a class that inherits from the GridView class to build a PoweredGridView control.

 

Then, following the Properties & Overrides paradigm, you must define new properties to carry the caption of each link command. You can see one of those property implementations in Figure 2, where the property value is stored in the ViewState to preserve it in the post backs. Note that you can define a default value for the property that will be used if you don t specify a value in the GridView declaration or elsewhere in code. In addition to the EditLinkButtonText, it would also be a good idea to create one more property that maps to the confirm message that will be displayed to the user when they try to delete a data row.

 

C#

[Description("Get or Set Link Button text"),

Category("Behavior"), DefaultValue("Modifica")]

public string EditLinkButtonText

{

 get

 {

 object o = ViewState["EditLinkButtonText"];

 return (o != null ?) o.ToString() : "Modifica";

 }

 set { ViewState["EditLinkButtonText"] = value; }

}

 

VB.NET

Public Property EditLinkButtonText() As String

 Get

 Dim o As Object = ViewState("EditLinkButtonText")

 If (IsNothing(o)) Then

  Return "Modifica"

 Else

  Return CStr(o)

 End If

 End Get

 Set(ByVal value As String)

 ViewState("EditLinkButtonText") = value

 End Set

End Property

Figure 2: The EditLinkButtonText property stores the caption of the Edit command.

 

Once you ve defined the properties, you have to manage them. Because the link commands are added to every data row, you must override the OnRowCreated method. The command links are displayed on the first column of every data row, so first you must check if the current row is a data row; then, if the first cell of the current row contains controls and the first control is a LinkButton, you must loop the control collection looking for every LinkButton. Every LinkButton has a command name associated to it, so a simple switch statement (select-case in VB.NET) can help in selecting which caption to override. The final step is to set the LinkButton Text property with the relative custom property value.

 

To manage the delete confirmation process, add a simple line of code in the switch delete branch that sets the OnClientClick property to specify additional client-side script that executes when the LinkButton control s Click event is raised. When the user clicks Delete a JavaScript confirmation dialog box will prompt them with the custom confirmation message you defined in the relative property (or the default value). If the user clicks the Yes button in the dialog box, the delete process is executed; otherwise the command is aborted and the page doesn t post back (see Figure 3).

 

C#

protected override void OnRowCreated(GridViewRowEventArgs e)

{

 if (e.Row.RowType == DataControlRowType.DataRow)

 {

 if (e.Row.Cells[0].Controls.Count > 0 &&

     e.Row.Cells[0].Controls[0] is LinkButton)

 {

  for (int i = 0; i < e.Row.Cells[0].Controls.Count; i++)

  {

   if (e.Row.Cells[0].Controls[i] is LinkButton)

   {

    LinkButton lb;

    lb = (LinkButton)e.Row.Cells[0].Controls[i];

    switch (lb.CommandName)

    {

     case "Edit":

      lb.Text = EditLinkButtonText;

      break;

     case "Update":

      lb.Text = UpdateLinkButtonText;

      break;

     case "Cancel":

      lb.Text = CancelLinkButtonText;

      break;

     case "Delete":

      lb.Text = DeleteLinkButtonText;  

      lb.OnClientClick = "return confirm('" +

                          ConfirmDeleteMessage + "');";

      break;

     case "Select":

      lb.Text = SelectLinkButtonText;

      break;

    }

   }

  }

 }

 }

 base.OnRowCreated(e);

}

 

VB.NET

Protected Overrides Sub _

 OnRowCreated(ByVal e As GridViewRowEventArgs)

 If (e.Row.RowType = DataControlRowType.DataRow) Then

 If (e.Row.Cells(0).Controls.Count > 0 And _

   TypeOf (e.Row.Cells(0).Controls(0)) Is LinkButton) Then

  For i As Integer = 0 To e.Row.Cells(0).Controls.Count - 1

   If TypeOf (e.Row.Cells(0).Controls(i)) _

      Is LinkButton Then

    Dim lb As LinkButton = _

    CType(e.Row.Cells(0).Controls(i), LinkButton)

    Select Case lb.CommandName

      Case "Edit"

      lb.Text = EditLinkButtonText

     Case "Update"

      lb.Text = UpdateLinkButtonText

     Case "Cancel"

      lb.Text = CancelLinkButtonText

     Case "Delete"

      lb.Text = DeleteLinkButtonText

      lb.OnClientClick = "return confirm('" + _

                          ConfirmDeleteMessage + "');"

     Case "Select"

      lb.Text = SelectLinkButtonText

     End Select

    End If

   Next

  End If

 End If

 MyBase.OnRowCreated(e)

End Sub

Figure 3: Override the OnRowCreated method to customize link command captions.

 

PoweredGridView at Work

To see the new PoweredGridView in action, first compile the class in a class library dll, then use it inside an aspx page (you can find the entire Visual Studio 2005 solution in the accompanying download files; see end of article for details).

 

The PoweredGridView control will bind to a table of the AdventureWorks sample database that ships with SQL Server 2005 (to run this example you can download Microsoft SQL Server 2005 Express Edition at http://www.microsoft.com/downloads/details.aspx?familyid=220549b5-0b07-4448-8848-dcc397514b41&displaylang=en and the AdventureWorks sample database at http://www.microsoft.com/downloads/details.aspx?familyid=9697AAAA-AD4B-416E-87A4-A8B154F92787&displaylang=en).

 

Remember to add a SQL Server login so the connection string you find in web.config file works correctly; otherwise, change the connection string with a suitable log-in account:

 

ID=adWorksUser;Password=passguor

 

To use the new control inside the page, you must register it at Page level with a Register directive, which creates an association between a tag prefix and the control:

 

<%@ Register Assembly="Powered01Cs"

   Namespace="Powered01Cs" TagPrefix="Powered01Cs" %>

 

<%@ Register Assembly="Powered01Vb"

   Namespace="Powered01Vb" TagPrefix="Powered01Vb" %>

 

At this point you can use it like any other control that shows the control declaration, as you can see in Figure 4.

 

<Powered03Cs:PoweredGridView ID="GridView1" runat="server"

 DataSourceID="SqlDataSource1" AutoGenerateColumns="false"

   AutoGenerateDeleteButton="true"

   AutoGenerateEditButton="true"

   AutoGenerateSelectButton="true" DataKeyNames="VendorId"

   SelectedRowStyle-CssClass="GRDSelectedItem"

   AlternatingRowStyle-CssClass="GRDAlternatingItem"

   RowStyle-CssClass="GRDItem"

   HeaderStyle-CssClass="GRDHeader"

   BorderColor="black" BorderWidth="1" GridLines="Both"

   AllowPaging="true" PageSize="20"

   SelectLinkButtonText="w hlen"

   DeleteLinkButtonText="Delete"

   CancelLinkButtonText="suprimir"

   UpdateLinkButtonText="p ivitt "

>

<Columns>

   <asp:BoundField DataField="VendorId"

    HeaderText="Id" ReadOnly="true" />

   <asp:BoundField DataField="AccountNumber"

    HeaderText="Account Number" />

   <asp:BoundField DataField="Name" HeaderText="Name" />

</Columns>

</Powered03Cs:PoweredGridView>

Figure 4: The PoweredGridView declaration where you define custom link command captions.

 

Now that you ve defined all the link command captions, leave the default delete confirmation message. Figure 5 shows the control at work.

 


Figure 5: PoweredGridView at work.

 

A Multilingual Grid

Some of you are probably wondering why it s necessary to define properties to manage an overwrite process when you can simply hard code new values on the OnRowCreated method. Well, first of all, it s better never to hard code values. Using properties makes it easier to change the text value if the customer wishes or if you need to deploy the application in multiple languages.

 

For large multilingual enterprise applications you should think about globalization, a concept for which the .NET Framework provides extensive support (for more information on globalization point your browser to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon/html/vxoriGlobalizationLocalizationNamespaces.asp).

 

For a simpler application you can manage multilingual behavior with themes, which are a collection of properties that define the appearance of pages and controls in your Web site (for more information on themes point your browser to http://msdn2.microsoft.com/en-us/library/wcyt4fxb.aspx).

 

A theme can include skin files, which define property settings for ASP.NET Web server controls; Figure 6 shows a skin file for the English version.

 

<%@ Register Assembly="Powered03Cs"

   Namespace="Powered03Cs"

   TagPrefix="Powered03Cs" %>

<Powered03Cs:PoweredGridView runat="server"

 SelectedRowStyle-CssClass="GRDSelectedItem"

 AlternatingRowStyle-CssClass="GRDAlternatingItem"

 RowStyle-CssClass="GRDItem"

 HeaderStyle-CssClass="GRDHeader"

 BorderColor="black" BorderWidth="1" GridLines="Both"

 EditLinkButtonText="Edit" CancelLinkButtonText="Cancel"

 UpdateLinkButtonText="Update"

 SelectLinkButtonText="Select"

 DeleteLinkButtonText="Delete"

 ConfirmDeleteMessage="Delete data?"

>

 <Columns>

 <asp:BoundField DataField="VendorId"

  HeaderText="Id" ReadOnly="true" />

 <asp:BoundField DataField="AccountNumber"

  HeaderText="Account Number" />

 <asp:BoundField DataField="Name" HeaderText="Name" />

 </Columns>

</Powered03Cs:PoweredGridView>

Figure 6: A skin file for the PoweredGridView control.

 

Figure 7 shows a sample page where you can choose a language to see a localization version of the PoweredGridView control.

 


Figure 7: Choose a language and change the grid captions.

 

Conclusion

A real world problem was the starting point for this article, which demonstrated how to customize the command link caption in a GridView control and how to add a client-side confirmation dialog box to the delete command. I defined some guidelines for building new controls with the Properties & Overrides paradigm and explained how to define custom control behaviors and where to implement them. Finally, you saw that customizing the GridView using this method is not only a way to display captions in your language but is also a way to prepare your application for use in a multilingual environment.

 

The sample code accompanying this article is available for download.

 

Oscar Peli is a .NET Solution Architect and the Mobile Devices chief in Ancona Town Council (Italy). An assistant at Macerata University, he develops Web-based applications to support research projects (http://reti.unimc.it). You can reach him at mailto:opeli@unimc.it.