Tuesday, April 29, 2008

How to Display Row Icon in DataGridView

Level: Intermediate
Knowledge Required:
  • DataGridView Control
  • Data Bindings
  • DataGridView Columns

Description:

We usually use DataGridView control to display contents of a DataTable. For a good impression and User Friendly Interface, we display an Icon with each Row in the DataGridView. For Example we can have a DataTable to store Tasks. Each task can have Status = Done / NOT Done. So we want that when we display these tasks in the DataGridView control there should be an Icon representing the Status of Task. As shown in the following figure.


DataGridView Control with Row Status Icon

To get the above result we will add an Unbound Column in the DataGridView control of Type DataGridViewImageColumn and set the VirtualMode property of DataGridView control to True. This will cause the DataGridView to fire the CellValueNeeded event. This Event triggers whenever the Cell is going to be rendered. Note that only the Unbound Cell will cause this event to be triggered. The bound columns will render themselve automatically.

For this purpose we first have created a Typed DataSet i.e. TaskDataSet containing a DataTable Task as,

Task DataTable

In the above table Task_Status is an Int32 field. We have decided that when this field is 0 (zero) then it means task is NOT Done yet and if this field contains 1 then it means task is Done.

Next we will create a Form and will put the following things:

  • TaskDataSet
  • BindingSource
  • DataGridView Control

Then we will bind the DataGridView to the BindingSource.

After this we will setup our DataGridView control by removing the Columns: Task_ID and Task_Status then we will add an Unbound Column TaskStatusIconColumn of type DataGridViewImageColumn. This column should be the first column of DataGridView set its properties as,

Properties of TaskStatusIconColumn:

  • DefaultCellStyle:
    • BackColor = White
    • ForeColor = Black
    • SelectionBackColor = White
    • SelectedForeColor = Black
  • Resizable = False
  • Width = 32

Now set the properties of Task_Description column which should have the Name TaskDescriptionDataGridViewTextBoxColumn.

Properties of TaskDescriptionDataGridViewTextBoxColumn:

  • AutoSizeMode = Fill

Properties of DataGridView Control:

  • RowHeadersVisible = False
  • SelectionMode = FullRowSelect
  • VirtualMode = True

VirtualMode is an important property here which must be True otherwise the CellValueNeeded event will NOT be triggered. And finally in the CellValueNeeded Event Handler we will use the following code:

Private Sub TaskDataGridView_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles TaskDataGridView.CellValueNeeded
    If e.RowIndex >= 0 AndAlso e.ColumnIndex = Me.TaskStatusIconColumn.Index Then
        Dim drvTask As DataRowView
        Dim rowTask As TaskDataSet.TaskRow
        drvTask = Me.TaskDataGridView.Rows(e.RowIndex).DataBoundItem
        rowTask = CType(drvTask.Row, TaskDataSet.TaskRow)
        Select Case rowTask.Task_Status
            Case 0 ' NOT Done
                e.Value = My.Resources.Resources.Blank16
            Case 1 ' Done
                e.Value = My.Resources.Resources.OK
        End Select
    End If
End Sub

In above code I have used a technique to get the DataRow of DataTable from DataGridView's Row. I have discussed this technique in my previous post How to Get the Table Row from DataGridView Row

Note that I have created 2 PNG images (Blank16 and OK) and have added them in my Resources. Blank16 is a Blank PNG if we dont use this, then DataGridView will render its default image i.e. a Red Cross

You can download the source from here:

DataGridViewRowStatusIcon.rar

2 comments:

Anonymous said...

This was great!!! my grids look awesome now. Thanks a whole lot for this post!!

Cheers,

ET

Stephen Oberholtzer said...

I needed to do this today, and this was most helpful. I did, however, discover an interesting additional tip:

If you want to leave the image display blank, do not set e.Value at all. Just leave it at its original value, and instead of the red "x" image, it will be blank.