Create a Reusable Custom Server Control

User-confirmed DataGrid Row Action

asp:Feature

LANGUAGES: C# | VB.NET

ASP.NET VERSIONS: 1.x

 

Create a Reusable Custom Server Control

User-confirmed DataGrid Row Action

 

By John H. Williams

 

Sometimes a seemingly simple user request can be quite tricky for a developer to implement. For instance, adding client-script functionality to ASP.NET server controls!

 

This article will demonstrate how to create a reusable custom server control. Specifically, we ll cover how to add Javascript code to a DataGrid item command button that will prompt a user for confirmation via an OK | Cancel dialog window. This is one of the more common requests I get from users in the form of a Delete button on a DataGrid that, upon clicking, will ask, Are you sure you want to delete this record?

 

Using this control will not require you to override the OnItemDataBound event of the DataGrid and call:

 

CType(e.Item.FindControl( MyButton ),

 Button).Attrinutes.Add( OnClick ,

  My Javascript Confirm Code )

 

In fact, you won t even have to write any code! Too good to be true? Let s find out.

 

First Things First

To get started, open Visual Studio.NET and create a blank solution named ConfirmDataGridRow . Choose the language with which you are most comfortable. Add a new Web Control Library project to the solution and call it MyControls . Create a new code file and name it ConfirmDataGridRow.cs (or ConfirmDataGridRow.vb ).

 

To keep things simple, copy and paste the code shown in Figure 1 into the newly blank code file.

 

using System;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.ComponentModel;

using MyControls.Common;

[assembly: System.Web.UI.TagPrefix("MyControls", "MyControls")]

namespace MyControls {

 ///

 /// Use this control within a datagrid row to attach

 /// javascript code to a button or link's client OnClick

 /// event to ask the user for confirmation

 ///

[ToolboxData("<{0}:ConfirmDataGridRow runat=server ItemIndexOffset=1

 ActionWord=Delete RowTypeName=Record

 HighlightColor=LemonChiffon ButtonID=>"),

   System.Drawing.ToolboxBitmap(typeof(System.Web.UI.WebControls.Button))

 ] 

 public class ConfirmDataGridRow : System.Web.UI.WebControls.WebControl {

 {

 }

}

Figure 1A: The basic shell for our server control (C#).

 

Imports System

Imports System.Drawing

Imports System.Web.UI

Imports System.Web.UI.WebControls

Imports System.ComponentModel

 "MyControls", "MyControls")>

Namespace MyControls

 

 ItemIndexOffset=1 ActionWord=Delete RowTypeName=Record

 HighlightColor=LemonChiffon ButtonID=>"), _

    ToolboxBitmap(GetType(System.Web.UI.WebControls.Button))> _

   Public Class ConfirmDataGridRow : Inherits WebControl

 

   End Class

End Namespace

Figure 1B: The basic shell for our server control (VB.NET).

 

Now we have a basic shell for our server control. To avoid straying from the topic at hand I won t get into specifics about how each line of code works. First, we need to add all the properties for our control (see Listing One). Now let s create our methods (see Figure 2). And finally, let s override the control s OnPreRender event (see Figure 3).

 

private Control GetParent(Control Child) {

 return Child.Parent;

}

private string GetClientScript() {

return this.DG.ClientID + ".rows[" + (this.DGItem.ItemIndex +

this.ItemIndexOffset) + "].style.backgroundColor = '" +

System.Drawing.ColorTranslator.ToHtml(this.HighlightColor) +

"';" + "if ( ! confirm('Are you sure you want to " +

this.ActionWord + " this " + this.RowTypeName + "?')) "+ "{" +

this.DG.ClientID + ".rows[" + (this.DGItem.ItemIndex +

this.ItemIndexOffset) + "].style.backgroundColor = '" +

System.Drawing.ColorTranslator.ToHtml(

this.DGItem.ItemType == ListItemType.AlternatingItem

? this.DG.AlternatingItemStyle.BackColor

: this.DG.ItemStyle.BackColor

) +

"';" +

"event.returnValue = false;" +

"}";

}

Figure 2A: Create the methods (C#).

 

Private Function GetParent(ByVal Child As Control) As Control

Return Child.Parent

End Function

Private Function GetClientScript() As String

Return Me.DG.ClientID + ".rows[" & (Me.DGItem.ItemIndex +

Me.ItemIndexOffset) & "]" & _ ".style.backgroundColor = '" &

System.Drawing.ColorTranslator.ToHtml(Me.HighlightColor) &

"';" & "if ( ! confirm('Are you sure you want to " &

Me.ActionWord & " this " & Me.RowTypeName + "?')) " & "

{" & Me.DG.ClientID & ".rows[" & (Me.DGItem.ItemIndex +

Me.ItemIndexOffset) & "].style.backgroundColor = '" & System.Drawing.ColorTranslator.ToHtml(IIf(Me.DGItem.ItemType =

ListItemType.AlternatingItem, Me.DG.AlternatingItemStyle.BackColor,

Me.DG.ItemStyle.BackColor)) & "';" & "event.returnValue = false;" & "}"

End Function

Figure 2B: Create the methods (VB.NET).

 

protected override void OnPreRender(EventArgs e) {

try {

   LinkButton LB = (LinkButton)this.DGItem.FindControl(

    this.ButtonID);

   LB.Attributes.Add("OnClick", this.GetClientScript());

 }

 catch {

   Button B = (Button)this.DGItem.FindControl(

    this.ButtonID);

    B.Attributes.Add("OnClick", this.GetClientScript());

 }

}

Figure 3A: Override the OnPreRender event (C#).

 

Protected Overloads Overrides Sub OnPreRender(

 ByVal e As EventArgs)

Try

 Dim LB As LinkButton = CType(

  Me.DGItem.FindControl(Me.ButtonID), LinkButton)

     LB.Attributes.Add("OnClick", Me.GetClientScript)

   Catch

     Dim B As Button = CType(

      Me.DGItem.FindControl(Me.ButtonID), Button)

   B.Attributes.Add("OnClick", Me.GetClientScript)

End Try

End Sub

Figure 3B: Override the OnPreRender event (VB.NET).

 

This method can be changed to suit your specific needs, but in my case I almost always use LinkButtons. OK, now that we re done creating the control, we need to create the Helpers class to support the control. Add a new code file named Helpers and put in it the code, as shown in Figure 4.

 

using System;

namespace ConfirmRowAction.Common {

 public class Helpers {

   static public object IsNull(object Obj) {

     if (Obj == null) { return ""; };

     if (Obj == DBNull.Value) { return ""; };

     if (Obj.ToString() == "") { return ""; };

     return Obj;

   }

   static public object IsNull(object Obj, object ReplaceValue) {

     if (Obj == null) { return IsNull(ReplaceValue);};

     if (Obj == DBNull.Value) { return IsNull(ReplaceValue);};

     if (Obj.ToString() == "") { return IsNull(ReplaceValue); };

     if (Obj.ToString() == "0") { return IsNull(ReplaceValue); };

     return Obj;

   }

   static public System.Data.DataTable SampleData() {

     System.Data.DataTable returnVal = new System.Data.DataTable(

      "SampleData");

     returnVal.Columns.Add("ID", typeof(int));

     returnVal.Columns.Add("Value_1", typeof(string));

     returnVal.Columns.Add("Value_2", typeof(string));

     returnVal.Columns.Add("Value_3", typeof(string));

     for (int i = 0; i < returnVal.Columns.Count; i++) {

       returnVal.Rows.Add(new object[]{i, "Value_1_" + i.ToString(),

         "Value_2_" + i.ToString(), "Value_3_" + i.ToString()});

     }

     return returnVal;

   }

 }

}

Figure 4A: Adding the Helpers file (C#).

 

Public Class Helpers

 Public Shared Function IsNull(ByVal Obj As Object) As Object

   If Obj Is Nothing Then

     Return ""

   End If

   If Obj Is DBNull.Value Then

     Return ""

   End If

   If Obj.ToString = "" Then

     Return ""

   End If

   Return Obj

 End Function

 Public Shared Function IsNull(

  ByVal Obj As Object, ByVal ReplaceValue As Object) As Object

   If Obj Is Nothing Then

     Return IsNull(ReplaceValue)

   End If

   If Obj Is DBNull.Value Then

     Return IsNull(ReplaceValue)

   End If

   If Obj.ToString = "" Then

     Return IsNull(ReplaceValue)

   End If

   If Obj.ToString = "0" Then

     Return IsNull(ReplaceValue)

   End If

   Return Obj

 End Function

 Public Shared Function SampleData() As System.Data.DataTable

   Dim returnVal As System.Data.DataTable =

    New System.Data.DataTable("SampleData")

   returnVal.Columns.Add("ID", GetType(Integer))

   returnVal.Columns.Add("Value_1", GetType(String))

   returnVal.Columns.Add("Value_2", GetType(String))

   returnVal.Columns.Add("Value_3", GetType(String))

   Dim i As Integer

   For i = 0 To returnVal.Columns.Count - 1

     returnVal.Rows.Add(New Object() {i, "Value_1_" +

      i.ToString, "Value_2_" + i.ToString, "Value_3_" +

      i.ToString})

   Next i

   Return returnVal

 End Function

End Class

Figure 4B: Adding the Helpers file (VB.NET).

 

The Next Step

Next, we are going to use the control on an ASP.NET Web form. For starters, let s build the project. If all is well, we should open a file explorer window and browse to the output dll. Copy it from there to a central location; for instance, C:\Projects\Components.

 

Now open a new Visual Studio.NET instance and create a new Web project called ConfirmRowAction . For this example we ll simply use the default WebForm1.aspx.

 

Now let s go to the toolbox; right-click and choose Customize Toolbox. Select the .Net Framework Components tab and choose Browse. Find the file you copied a few steps ago and select it. Click the OK button; you should now be looking at the toolbox with a newly added item. Now let s go to the HTML view of the Web form and create a DataGrid (see Figure 5).

 

 "server" AutoGenerateColumns="False">

 

 

  "LightGray">

 "White" BackColor="#006699">

 

   

    "ID">

   

    "Value 1">

   

    "Value 2">

   

    "Value 3">

   

     

       

        "server">Delete

     

   

   

     

       

        "Delete">

     

   

 

Figure 5: Create a DataGrid in the HTML view of the Web form.

 

Switch back to Design view and right-click on the DataGrid and choose Edit Template | Columns[4] (see Figure 6). It will then go into edit mode of the column; we want to focus the cursor position inside the Item Template (see Figure 7).

 


Figure 6: The context menu of the DataGrid and which option to choose.

 


Figure 7: The delete template column in edit mode.

 

Now let s go to the toolbox and double-click the newly added item (named ConfirmRowAction); see Figure 8.

 


Figure 8: The newly added item in the toolbox.

 

You should now be looking at the edit template column again, this time with the new control selected. Now switch back to HTML view; we should see the following:

 

 "ConfirmDataGridRow1" runat="server"

 ButtonID="lbDelete"

 HighlightColor="LemonChiffon"

 RowTypeName="Record"

 ActionWord="Delete"

 ItemIndexOffset="1">

 

All we have to do is set the ButtonID property to the ID of the button to which we want to add the Confirm event. In this case, it should be lbDelete .

 

We already have the tagprefix registered (from adding the one above), so we can simply copy and paste the HTML above and paste it in the next column of the DataGrid. All we need to do is change the ButtonID property from lbDelete to cmdDelete.

 

One more final step is to put some data in this DataGrid. If you remember creating the Helpers class in the control then you may remember the function called SampleData; this will be used to put data in the grid.

 

So we want to get to the code-behind of the Web form and the code shown in Figure 9 in the page load event.

 

private void Page_Load(object sender, System.EventArgs e) {

 if(! this.IsPostBack) {

 this.dgConfirm.DataSource =

  ConfirmRowAction.Common.Helpers.SampleData();

 this.dgConfirm.DataBind();

 }

}

Figure 9A: Binding the datagrid to the sample data (C#).

 

Private Sub Page_Load(ByVal sender As System.Object, ByVal

 e As System.EventArgs) Handles MyBase.Load

If Not Me.IsPostBack Then

With Me.dgConfirm

 .DataSource =

   MyControls.ConfirmDataGridRow.Helpers.SampleData.DataBind()

End With

End If

End Sub

Figure 9B: Binding the datagrid to the sample data (VB.NET).

 

Build the Web project and view it in the browser. You should now see a DataGrid with Delete links and normal Delete buttons (see Figure 10). Click on any of them and watch the magic!

 


Figure 10: The control in action!

 

If you select the Cancel button the page will not post back to the server. If you choose OK, the Web form will post and it s up to you how to handle that event. From now on all you have to do is click and drag the item from the toolbar and set the ButtonID property. It s very easy! Happy coding.

 

The C# and VB.NET sample code accompanying this article is available for download.

 

John H. Williams is a Senior Programmer who works for Ajilon Consulting Inc. developing .NET applications for Fortune 500 companies in the Baltimore, MD area.

 

Begin Listing One

(C#)

private string _ButtonID;

 ///

 /// Use this property to change which row is highlighted

 /// based on the item index. If a row above the desired

 /// row is being highlighted then you need to increment

 /// this value. If a row is below the desired row then you

 /// should decrement this value.

 ///

 public int ItemIndexOffset {

 get {

  if (this.ViewState["ItemIndexOffset"] == null)

   { return 2; }

  else return (int)this.ViewState["ItemIndexOffset"];

 }

 set { this.ViewState["ItemIndexOffset"] = value; }

 }

 ///

 /// Set this to the color you want the row to be

 /// highlighted upon clicking the action button.

 ///

 public System.Drawing.Color HighlightColor {

 get {

  if (this.ViewState["HighlightColor"] == null) {

    return System.Drawing.Color.LemonChiffon;

  }

  return (

   System.Drawing.Color)this.ViewState["HighlightColor"];

 }

 set { this.ViewState["HighlightColor"] = value;  }

 }

 ///

 /// Sets the [ActionWord] of the following:

 /// "Are you sure you want to [ActionWord]

 /// this [RowTypeName]?"

 ///

 public string ActionWord {

 get {return (string)Helpers.IsNull(

      this.ViewState["ActionWord"]);}

 set {this.ViewState["ActionWord"] = value;}

 }

 ///

 /// Sets the [RowTypeName] of the following "Are you

 /// sure you want to [ActionWord] this [RowTypeName]?"

 ///

 public string RowTypeName {

 get {return (string)Helpers.IsNull(

      this.ViewState["RowTypeName"]);}

 set {this.ViewState["RowTypeName"] = value;}

 }

 ///

 /// Set this to the button control's id property of which

 /// you want to attach the confirmation to.

 ///

 public string ButtonID {

 get{return this._ButtonID;}

 set{this._ButtonID = value;}

 }

 private DataGrid DG {

 get {

   Control Child;

   Child = this.Parent;

   while (1 == 1) {

     if (Child.GetType() == typeof(

         System.Web.UI.WebControls.DataGrid)) {

       return (DataGrid)Child;

     } else {

       Child = this.GetParent(Child);

     }

   }

 }

 }

 private DataGridItem DGItem {

 get {

   Control Child;

   Child = this.Parent;

   while (1 == 1) {

     if (Child.GetType() == typeof(

         System.Web.UI.WebControls.DataGridItem)) {

       return (DataGridItem)Child;

     } else {

       Child = this.GetParent(Child);

     }

   }

 }

 }

 

 

(VB.NET)

Private _ButtonID As String

 Public Property ItemIndexOffset() As Integer

 Get

   If Me.ViewState("ItemIndexOffset") Is Nothing Then

       Return 1

   Else

       Return Me.ViewState("ItemIndexOffset")

   End If

 End Get

 Set(ByVal Value As Integer)

   Me.ViewState("ItemIndexOffset") = Value

 End Set

 End Property

 Public Property HighlightColor() As System.Drawing.Color

 Get

   If Me.ViewState("HighlightColor") Is Nothing Then

       Return System.Drawing.Color.LemonChiffon

   End If

   Return CType(Me.ViewState(

                "HighlightColor"), System.Drawing.Color)

 End Get

 Set(ByVal Value As System.Drawing.Color)

   Me.ViewState("HighlightColor") = Value

 End Set

 End Property

 Public Property ActionWord() As String

 Get

   Return CType(Helpers.IsNull(Me.ViewState(

                "ActionWord")), String)

 End Get

 Set(ByVal Value As String)

   Me.ViewState("ActionWord") = Value

 End Set

 End Property

 Public Property RowTypeName() As String

 Get

   Return CType(Helpers.IsNull(Me.ViewState(

                "RowTypeName")), String)

 End Get

 Set(ByVal Value As String)

   Me.ViewState("RowTypeName") = Value

 End Set

 End Property

 Public Property ButtonID() As String

 Get

   Return Me._ButtonID

 End Get

 Set(ByVal Value As String)

   Me._ButtonID = Value

 End Set

 End Property

 Private ReadOnly Property DG() As DataGrid

 Get

   Dim Child As Control

   Child = Me.Parent

   While 1 = 1

       If Child.GetType Is GetType(

        System.Web.UI.WebControls.DataGrid) Then

           Return CType(Child, DataGrid)

       Else

             Child = Me.GetParent(Child)

       End If

   End While

 End Get

 End Property

 Private ReadOnly Property DGItem() As DataGridItem

 Get

   Dim Child As Control

   Child = Me.Parent

   While 1 = 1

    If Child.GetType Is GetType(

      System.Web.UI.WebControls.DataGridItem) Then

        Return CType(Child, DataGridItem)

      Else

       Child = Me.GetParent(Child)

      End If

  End While

 End Get

 End Property

End Listing One

 

 

 

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish