Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Create a Custom DataGridView Column : Page 2

Creating custom column types for the DataGridView control isn't nearly as tricky as it once was.

Getting Started Creating the Example
Start by creating a new Windows Application project in Visual Studio 2005. Next, create a new data source: Select Data --> Add New Data Source. Create a data source that retrieves at least a few columns, one of which is an integer column. The example shown here uses the ProductID, ProductName, and UnitsInStock fields from the Northwind Products table. Make sure the Data Sources window is visible (select Data --> Show Data Sources if it's not), open the project's single form in the form designer, and drag the entire table over to the form. Visual Studio creates a DataGridView control on the form for you (along with the standard Windows Forms data binding plumbing, including DataSet, BindingSource, and TableAdapter instances). From the DataGridView control's smart tag, select Dock in Parent Container. Finally, save the project and run the form to verify that you see the raw data in your DataGridView control.

Now that you have the basics worked out, I'll assume you're using the same fields as shown in Figure 1 for the remainder of the demo. To get started with the real work, add a new class named DataGridViewBarGraphColumn to your project, and have the class inherit from the DataGridViewColumn class. Modify the class code to the following, adding stubs so that you can continue creating the custom cell type. You'll come back and complete this class later.

[Visual Basic] Public Class DataGridViewBarGraphColumn Inherits DataGridViewColumn Public MaxValue As Long Private needsRecalc As Boolean = True Public Sub CalcMaxValue() End Sub End Class [C#] public class DataGridViewBarGraphColumn : DataGridViewColumn { public DataGridViewBarGraphColumn(){} public long MaxValue; private bool needsRecalc = true; public void CalcMaxValue() {} }

Next, add a new class to your project named DataGridViewBarGraphCell. In this case, because you want to emulate the behavior of the standard text box cell, you'll need your class to inherit from the DataGridViewTextBoxCell class. (This class takes care of such tasks as drawing the cell's background and content, which you'll find useful.) In C#, you'll need to add the using statements to the top of the file, as shown in the code snippet below:

[Visual Basic] Public Class DataGridViewBarGraphCell Inherits DataGridViewTextBoxCell End Class [C#] // Add these to your file: using System.Drawing; using System.Windows.Forms; // Your class should look like this: public class DataGridViewBarGraphCell : DataGridViewTextBoxCell { }

The Paint method is the only base class method you need to override. Type just enough of the method declaration inside the class to let Visual Studio know your intentions, and then let the tools fill in the details. You need to type only the following code, before pressing Tab:

[Visual Basic] Overrides Paint [C#] public override Paint

At that point, Visual Studio completes the declaration, rearranged here to fit the available space (I've also removed extraneous namespace references, to make the code easier to read):

[Visual Basic] Protected Overrides Sub Paint( _ ByVal graphics As Graphics, _ ByVal clipBounds As Rectangle, _ ByVal cellBounds As Rectangle, _ ByVal rowIndex As Integer, _ ByVal cellState As DataGridViewElementStates, _ ByVal value As Object, _ ByVal formattedValue As Object, _ ByVal errorText As String, _ ByVal cellStyle As DataGridViewCellStyle, _ ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _ ByVal paintParts As DataGridViewPaintParts) MyBase.Paint(graphics, clipBounds, cellBounds, _ rowIndex, cellState, value, _ formattedValue, errorText, cellStyle, _ advancedBorderStyle, paintParts) End Sub [C#] protected override void Paint( Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); }

As you can see, the DataGridView control passes a large amount of information to the DataGridViewTextBoxCell class (and your class, by inheritance) as it paints each cell in the grid. Table 1 describes each of the parameters your Paint method override receives.

Table 1. DataGridViewTextBoxCell Paint Method Parameters: The table lists the parameters to the Paint method along with a brief description of each.




A Graphics object you can use when painting your cell.


A Rectangle that represents the area of the DataGridView control that needs to be repainted.


A Rectangle that represents the area of the cell in which you're drawing.


The row index of the cell you're drawing.


A bitwise combination of DataGridViewElementStates values (Displayed, Frozen, None, ReadOnly, Resizable, ResizableSet, Selected, Visible) indicating the state of the cell.


The data of the cell that you're painting, as an object.


The formatted value for the cell you're painting, as an object.


The error message associated with the cell.


A DataGridViewCellStyle instance that contains formatting and style information about the cell.


A DataGridViewAdvancedBorderStyle instance that contains information about the border style for the cell.


A bitwise combination of DataGridViewPaintParts values (All, Background, Border, ContentBackground, ContentForeground, ErrorIcon, Focus, None, SelectionBackground) that indicates the parts of the cell that need to be repainted.

For this example, you won't need to use many of the Paint method parameters, but it's nice to know exactly what tools you have to work with, if you want to create more complex cell types.

This example is relatively simple—all you need to do is draw the bar and the formatted value, side by side. Of the parameters listed in Table 1, you'll only need the cellBounds, cellState, value, and formattedValue for this example.

To get started, within the Paint method override that you've already created, modify the call to the base class' Paint method, removing the formattedValue from the list of parameters. Because you're going to draw the value, you don't want the cell to do it itself:

[Visual Basic] MyBase.Paint(graphics, clipBounds, cellBounds, _ rowIndex, cellState, _ value, "", errorText, cellStyle, _ advancedBorderStyle, paintParts) [C#] base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, "", errorText, cellStyle, advancedBorderStyle, paintParts);

Continue by adding code that retrieves the cell's value. If the value is DBNull, treat it as 0. If the value is 0, change it so that it's 1 (that way, even if the value is 0, you'll see a single-pixel-wide vertical bar). If you don't care for this behavior, you can leave out the simple conversion:

[Visual Basic] ' Get the value of the cell: Dim cellValue As Decimal If IsDBNull(value) Then cellValue = 0 Else cellValue = CDec(value) End If ' If cell value is 0, you still want to ' show something, so set the value to 1. If cellValue = 0 Then cellValue = 1 End If [C#] // Get the value of the cell: decimal cellValue = 0; if (Convert.IsDBNull(value)) cellValue = 0; else cellValue = Convert.ToDecimal(value); // If cell value is 0, you still want to // show something, so set the value to 1. if (cellValue == 0) cellValue = 1;

Add two constants that control the offset from the left, and the width between the bar and the text. You can modify these values, if you like:

[Visual Basic] Const HORIZONTALOFFSET As Integer = 1 Const SPACER As Integer = 4 [C#] const int HORIZONTALOFFSET = 1; const int SPACER = 4;

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date