Rahul Soni's blog

Never assume the obvious is true!

Dynamic Datagrid Series - 4.Multiselect Datagrid behaving like most other Mail Service's Datagrid

Dynamic Datagrid Series - 4.Multiselect Datagrid behaving like most other Mail Service's Datagrid

  • Comments 4

Requirement 4
=============
This is the 4th requirement of the Dynamic Datagrid Series at my blog. For previous Requirements, click here.
Till now, we have a datagrid which is dynamically created with nicely formatted columns and rows which changes color whenever the mouse is hovered over any row!

We need 3 more things now...


1) Add Checkboxes in the first column of our datagrid
2) Whenever we check on the "Header" Checkbox all checkboxes in the other rows should get checked and vice versa.
3) There should be a way to list out all the checked rows so that we could do the *processing* on them at one shot.
4) For robustness, we want postback to happen only on the Header Checkbox.

In a nutshell, it should behave as a Yahoo Mail's or most other mail datagrids behave. Here is what the output looks like...

Let's create a new ASP.NET Web Application under Visual Basic Projects called DataGridDemo4.
Add the following lines just after your <configuration> tag in the web.config. I will be working with the "pubs" database all
the time. Better to have it in the web.config.

 <appSettings>
  <add key="ConnectionInfo" value="server=(local);database=Pubs;user id=sa;password="/>
 </appSettings>

1) Create a new Page called "MultiSelectGrid.aspx"
2) Drag and drop a PlaceHolder control and change the ID to "PlaceHolder". Go to the code behind of this page and delete everything. Now paste the following...

Imports System.Data
Imports System.Data.SqlClient
Imports System.Text
'
Public Class CheckBoxTemplate
    Implements ITemplate
    '
    Private i As Integer
    Private chkBox As CheckBox
    Private strID As String
    Private strText As String
    Private blnChecked As Boolean
    Private blnAutoPostBack As Boolean
    '
    Sub New(ByVal ID As String, _
        ByVal Text As String, _
        ByVal Checked As Boolean, _
        ByVal AutoPostBack As Boolean _
    )
        '
        strID = ID
        strText = Text
        blnChecked = Checked
        blnAutoPostBack = AutoPostBack
    End Sub
    '
    Public Sub InstantiateIn( _
        ByVal container As System.Web.UI.Control _
    ) Implements System.Web.UI.ITemplate.InstantiateIn
        '
        chkBox = New CheckBox()
        chkBox.ID = strID + i.ToString
        chkBox.Text = strText
        chkBox.Checked = blnChecked
        chkBox.AutoPostBack = blnAutoPostBack
        'The following AddHandler is just to ensure that the Checked Changed is not fired
        'for all the checkbox controls. If that happens, you will get weird out. Try
        'commenting the following If and End If and you will come to know ;o)
        If strID = "Header" Then
            AddHandler chkBox.CheckedChanged, AddressOf chkCheckBox_CheckedChanged
        End If
        i += 1
        container.Controls.Add(chkBox)
    End Sub
    '
    Private Sub chkCheckBox_CheckedChanged( _
        ByVal sender As System.Object, _
        ByVal e As System.EventArgs _
    )
        Dim chkBox As CheckBox
        Dim dgiItem As DataGridItem
        Dim dgGrid As DataGrid
        Dim blnIsHeaderChecked As Boolean
        chkBox = CType(sender, CheckBox)
        blnIsHeaderChecked = chkBox.Checked
        dgiItem = chkBox.NamingContainer()
        dgGrid = dgiItem.NamingContainer()
        For Each dgiItem In dgGrid.Items
            chkBox = CType(dgiItem.Cells(0).Controls(0), CheckBox)
            chkBox.Checked = blnIsHeaderChecked
        Next
    End Sub
End Class
'
Public Class MultiSelectGrid
    Inherits System.Web.UI.Page
    '
#Region " Web Form Designer Generated Code "
    '
    'This call is required by the Web Form Designer.
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
    End Sub
    '
    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
        'CODEGEN: This method call is required by the Web Form Designer
        'Do not modify it using the code editor.
        InitializeComponent()
    End Sub
#End Region
    '
    Protected WithEvents PlaceHolder As System.Web.UI.WebControls.PlaceHolder
    Dim dg As New DataGrid()
    Dim btnShowChecked As New Button()
    Dim strConn As String = ConfigurationSettings.AppSettings("ConnectionInfo")
    Dim strCommand As String = "select top 10 au_id as Author_ID, au_lname as " & _
    "Last_Name, au_fname as First_Name, phone as Phone_Number, state as State " & _
    "from authors"
    '
    Private Sub Page_Load(ByVal sender As System.Object, _
        ByVal e As System.EventArgs _
    ) Handles MyBase.Load
        '
        'Put user code to initialize the page here
        Dim tblData As DataTable
        tblData = GetData(strCommand, strConn)
        dg.DataSource = tblData
        dg.ID = "DataGrid1"
        dg.AutoGenerateColumns = False
        AddHandler dg.ItemCreated, AddressOf DataGrid_ItemCreated
        AddCheckBoxColumn()
        FormatColumns(tblData)
        dg.DataBind()
        PlaceHolder.Controls.Add(dg)
        FormatDataGrid()
        btnShowChecked.Text = "Show Checked"
        AddHandler btnShowChecked.Click, AddressOf btnShowChecked_Click
        PlaceHolder.Controls.Add(btnShowChecked)
    End Sub
    '
    Private Sub AddCheckBoxColumn()
        '
        Dim chkColumn As New TemplateColumn()
        '
        chkColumn.HeaderTemplate = New CheckBoxTemplate("Header", "", False, True)
        chkColumn.ItemTemplate = New CheckBoxTemplate("Item", "", False, False)
        chkColumn.HeaderStyle.Width = New Unit(5)
        chkColumn.ItemStyle.Width = New Unit(5)
        dg.Columns.Add(chkColumn)
    End Sub
    '
    Protected Sub DataGrid_ItemCreated( _
        ByVal sender As Object, _
        ByVal e As System.Web.UI.WebControls.DataGridItemEventArgs _
    )
        '
        'Since we are using alternate colors and won't like to miss out on the colors,
        'we need to add the attributes such that it reverts back whatever color was used before.
        Dim Remainder As Integer
        Remainder = e.Item.ItemIndex Mod 2
        Select Case Remainder
            Case -1 'It is a header
            Case 0 'Item
                e.Item.Attributes.Add("OnMouseOver", "this.style.backgroundColor = 'beige';")
                e.Item.Attributes.Add("OnDblClick", "alert('" & e.Item.Cells(0).Controls(0).ID & "');")
                e.Item.Attributes.Add("OnMouseOut", "this.style.backgroundColor = 'cyan';")
            Case 1  'Alternate Item
                e.Item.Attributes.Add("OnMouseOver", "this.style.backgroundColor = 'beige';")
                e.Item.Attributes.Add("OnDblClick", "alert('" & e.Item.Cells(0).Controls(0).ID & "');")
                e.Item.Attributes.Add("OnMouseOut", "this.style.backgroundColor = '#CED8FD';")
        End Select
    End Sub
    '
    Protected Sub btnShowChecked_Click( _
        ByVal sender As Object, _
        ByVal e As System.EventArgs _
    )
        Dim strSelectedItems As New StringBuilder()
        Dim diDataGridItem As DataGridItem
        Dim chkBox As CheckBox
        '
        For Each diDataGridItem In dg.Items
            chkBox = CType(diDataGridItem.Cells(0).Controls(0), CheckBox)
            If chkBox.Checked Then
                strSelectedItems.Append("<B>ID = </B>")
                strSelectedItems.Append(diDataGridItem.Cells(1).Text)
                strSelectedItems.Append(" <B>Name = </B>")
                strSelectedItems.Append(diDataGridItem.Cells(2).Text)
                strSelectedItems.Append("<BR>")
            End If
        Next
        Response.Write(strSelectedItems.ToString)
    End Sub
    '
    Private Sub FormatDataGrid()
        '
        dg.CellPadding = 5
        dg.BorderColor = Color.Black
        'Set Font settings
        dg.Font.Name = "Arial"
        dg.Font.Size = New FontUnit(10)
        'Show Header and Footer
        dg.ShowHeader = True 'Default is true
        'Set Header Style
        dg.HeaderStyle.Font.Bold = True
        dg.HeaderStyle.BackColor = Color.DarkGray
        dg.HeaderStyle.ForeColor = Color.Black
        dg.HeaderStyle.HorizontalAlign = HorizontalAlign.Center
        dg.HeaderStyle.VerticalAlign = VerticalAlign.Middle
        'Set Item Style
        dg.ItemStyle.BackColor = Color.Cyan
        dg.ItemStyle.ForeColor = Color.Black
        'Set Alternating Item Style
        dg.AlternatingItemStyle.BackColor = Color.FromArgb(206, 216, 253) 'In Hex = #CED8FD
        dg.AlternatingItemStyle.ForeColor = Color.Black
    End Sub
    '
    Private Sub FormatColumns(ByRef tblData As DataTable)
        '
        Dim colDataColumn As DataColumn
        For Each colDataColumn In tblData.Columns()
            dg.Columns.Add(CreateBoundColumns(colDataColumn))
        Next
    End Sub
    '
    Private Function GetData(ByVal strCommand As String, _
        ByVal strConn As String _
    ) As DataTable
        '
        Dim adpSQLAdapter As New SqlDataAdapter(strCommand, strConn)
        Dim tblData As New DataTable()
        '
        adpSQLAdapter.Fill(tblData)
        Return tblData
    End Function
    '
    Private Function CreateBoundColumns( _
        ByRef colDataColumn As DataColumn _
    ) As DataGridColumn
        '
        Dim bndColumn As New BoundColumn()
        '
        bndColumn.DataField = colDataColumn.ColumnName
        bndColumn.HeaderText = colDataColumn.ColumnName.Replace("_", " ")
        bndColumn.DataFormatString = SetFormatString(colDataColumn)
        Return bndColumn
    End Function
    '
    Private Function SetFormatString( _
        ByRef colDataColumn As DataColumn _
    ) As String
        '
        Dim strDataType As String
        '
        Select Case colDataColumn.DataType.ToString()
            Case "System.Int32"
                strDataType = "{0:#,###}"
            Case "System.Decimal"
                strDataType = "{0:c}"
            Case "System.DateTime"
                strDataType = "{0:dd-mm-yyyy}"
            Case "System.String"
                strDataType = ""
            Case Else
                strDataType = ""
        End Select
        Return strDataType
    End Function
End Class

3) Open Solution Explorer, right click on "MultiSelectGrid.aspx" and select "Set as Start Page" in the menu
4) Click on Debug -> Start and you should be able to see a table of Data from the Database which changes color whenever you
hover your mouse on the row. Apart from that, you will be able to select as many rows as you want. Moreover, you may check/uncheck the Header checkbox and every other checkbox will behave in the same fashion. Clicking on the "Show Checked" button will write every checked rows information using the StringBuilder

Attachment: MultiselectDatagrid.GIF
  • Hi Mr. Soni,
    I want to add the checkbox in vb.net (the same thing as you had developed for asp.net).
    How do i get in vb.net ?
    can you guide me with an answer ?
  • Hi Vijay...

    I have created a sample, which will show you how to do that! Just drag and drop a datagrid control in any new form and resize it accordingly. Now modify your Form_Load event as follows... 

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
           Dim connStr As String = "server=(local);database=Pubs;user id=sa;password="
           Dim cnnConnection As New SqlConnection(connStr)
           Dim strCommand As String = "select top 10 au_id as Author_ID, au_lname as " & _
           "Last_Name, au_fname as First_Name, phone as Phone_Number, state as State " & _
           "from authors"
           Dim daSqlDataAdapter As New SqlDataAdapter(strCommand, cnnConnection)
           Dim dsDataSet As New DataSet("myDataSet")
           Dim dtDataTable As DataTable
           Dim dtDataColumn As New DataColumn("CheckBox")
           '
           dtDataColumn.DataType = System.Type.GetType("System.Boolean")
           dtDataColumn.DefaultValue = True
           daSqlDataAdapter.Fill(dsDataSet)
           dtDataTable = dsDataSet.Tables(0)
           dtDataTable.Columns.Add(dtDataColumn)
           DataGrid1.DataSource = dsDataSet.Tables(0)
       End Sub

    Please don't forget to add the following lines on the top of your code-behind page...

    Imports System.Data
    Imports System.Data.SqlClient

    Hope that helps,
    -Rahul
  • The event is firing on Check but not when I uncheck the header checkbox. Any ideas?
  • Great piece of code!

    I had one unusual result when I allowed sorting on my datagrid.  

    The initial grid results worked well, I could check the boxes and select all the checked rows when done. After sorting I could not select any of the checked rows.  Visually they were checked but programmatically they all where marked as not checked.  What goes wrong is the InstantiateIn event is fired off once before the sort and then again after the sort.  The second time the number of check box rows is doubled.  When looping through the grid the first set of checkbox objects are tested not the second set that is viewable and clickable.

    What I did to circumvent this problem, on my sortcommand event I removed the checkbox column and added it back in.  When the newly sorted data is bound to the grid I have the correct number of checkboxes and I can successfully test them.

    See below:

    Private Sub dgSearchResults_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles dgSearchResults.SortCommand

           Dim SortBy As String = e.SortExpression

           Me.dgSearchResults.Columns.RemoveAt(0)

           Dim colbtnSelect As New TemplateColumn

           colbtnSelect.HeaderText = "Select"

           colbtnSelect.ItemTemplate = New CheckBoxTemplate("Item", "", False, False)

           colbtnSelect.HeaderStyle.HorizontalAlign = HorizontalAlign.Center

           colbtnSelect.ItemStyle.HorizontalAlign = HorizontalAlign.Center

           Me.dgSearchResults.Columns.AddAt(0, colbtnSelect)

           Me.dgSearchResults.Attributes("colbtnSelect") = 0

           BindGridSearchResults(SortBy, False)

    End Sub

Page 1 of 1 (4 items)
Leave a Comment
  • Please add 8 and 8 and type the answer here:
  • Post