Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Create a Custom DataGridView Column : Page 3

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


advertisement
Dealing with Geometry
Clearly, solving this programming problem introduces some mundane geometry issues, such as the width of the bar compared to the width of the largest bar. In addition, how much room is available for the largest bar, leaving room for the text associated with that bar?

To solve these issues, you'll need to be able to retrieve the maximum value for all the values in the column; the parent column should handle this chore for you. You can use the cell's OwningColumn property to retrieve a reference to the parent column. Add the following block of code (of course, the parent's CalcMaxValue and MaxValue members don't do much yet):

[Visual Basic] ' Get the parent column and the maximum value: Dim parent As DataGridViewBarGraphColumn = _ CType(Me.OwningColumn, DataGridViewBarGraphColumn) parent.CalcMaxValue() Dim maxValue As Long = parent.MaxValue [C#] // Get the parent column and the maximum value: DataGridViewBarGraphColumn parent = (DataGridViewBarGraphColumn)this.OwningColumn; parent.CalcMaxValue(); long maxValue = parent.MaxValue;

You can also now retrieve the font for the column, using the column's InheritedStyle property:

[Visual Basic] Dim fnt As Font = parent.InheritedStyle.Font [C#] Font fnt = parent.InheritedStyle.Font;

Author's Note: The DataGridView control's support for inheriting styles in cells and columns is quite rich. For more information, see the MSDN help topic, "Cell Styles in the Windows Forms DataGridView Control.")

To calculate the amount of space available in each cell, you'll need to know the width of the text for the maximum value. Given that width, you can calculate the maximum size for the bar in each cell. The Graphics.MeasureString method provides the value you need, so add the following code to calculate these values:



[Visual Basic] Dim maxValueSize As SizeF = _ graphics.MeasureString(maxValue.ToString, fnt) Dim availableWidth As Single = _ cellBounds.Width - maxValueSize.Width - _ SPACER - (HORIZONTALOFFSET * 2) [C#] SizeF maxValueSize = graphics.MeasureString(maxValue.ToString(), fnt); float availableWidth = cellBounds.Width - maxValueSize.Width - SPACER - (HORIZONTALOFFSET * 2);

Given the available width for the bars, you can calculate the width of the current cell's bar, using the ratio of the current value to the maximum value, scaled to fit within the available space. Add the following code to work this out:

[Visual Basic] cellValue = CDec((cellValue / maxValue) * _ availableWidth) [C#] cellValue = Convert.ToDecimal( (Convert.ToDouble(cellValue) / maxValue) * availableWidth);

It's time to start drawing content. Add the following code, which calculates the size of the bar and then draws it using a red brush:

[Visual Basic] ' Draw the bar, truncating to fit in the space ' you've got in the cell: Const VERTOFFSET As Integer = 4 Dim newRect As New RectangleF( _ cellBounds.X + HORIZONTALOFFSET, _ cellBounds.Y + VERTOFFSET, _ cellValue, _ cellBounds.Height - (VERTOFFSET * 2)) graphics.FillRectangle(Brushes.Red, newRect) [C#] const int VERTOFFSET = 4; RectangleF newRect = new RectangleF( cellBounds.X + HORIZONTALOFFSET, cellBounds.Y + VERTOFFSET, Convert.ToSingle(cellValue), cellBounds.Height - (VERTOFFSET * 2)); graphics.FillRectangle(Brushes.Red, newRect);

Next, add code that draws the text:

[Visual Basic] ' Get the text to draw and calculate its width: Dim cellText As String = formattedValue.ToString() Dim textSize As SizeF = _ graphics.MeasureString(cellText, fnt) ' Calculate where text would start: Dim textStart As PointF = _ New PointF( _ HORIZONTALOFFSET + cellValue + SPACER, _ (cellBounds.Height - textSize.Height) / 2) ' Calculate the correct color: Dim textColor As Color = _ parent.InheritedStyle.ForeColor If (cellState And _ DataGridViewElementStates.Selected) = _ DataGridViewElementStates.Selected Then textColor = parent.InheritedStyle.SelectionForeColor End If ' Draw the text: Using brush As New SolidBrush(textColor) graphics.DrawString(cellText, fnt, brush, _ cellBounds.X + textStart.X, _ cellBounds.Y + textStart.Y) End Using [C#] string cellText = formattedValue.ToString(); SizeF textSize = graphics.MeasureString(cellText, fnt); // Calculate where text would start: PointF textStart = new PointF( Convert.ToSingle(HORIZONTALOFFSET + cellValue + SPACER), (cellBounds.Height - textSize.Height) / 2); // Calculate the correct color: Color textColor = parent.InheritedStyle.ForeColor; if ((cellState & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected) { textColor = parent.InheritedStyle.SelectionForeColor; } // Draw the text: using (SolidBrush brush = new SolidBrush(textColor)) { graphics.DrawString(cellText, fnt, brush, cellBounds.X + textStart.X, cellBounds.Y + textStart.Y); }

This code starts by calculating where the text should start, and then creates a new Font object. Next, the code calculates the width of the text in the new font:

[Visual Basic] Dim cellText As String = formattedValue.ToString() Dim textSize As SizeF = _ graphics.MeasureString(cellText, fnt) [C#] string cellText = formattedValue.ToString(); SizeF textSize = graphics.MeasureString(cellText, fnt);

Next, the code calculates where the text should start within the cell, given the width of the bar and the various offsets, along with the height of the cell and the text:

[Visual Basic] Dim textStart As PointF = _ New PointF( _ HORIZONTALOFFSET + cellValue + SPACER, _ (cellBounds.Height - textSize.Height) / 2) [C#] PointF textStart = new PointF( Convert.ToSingle(HORIZONTALOFFSET + cellValue + SPACER), (cellBounds.Height - textSize.Height) / 2);

Of course, a selected cell displays text differently than a standard cell, so the code must determine if the cell has been selected and then set up the appropriate text color. This code uses the cellState parameter to do its work:

[Visual Basic] Dim textColor As Color = _ parent.InheritedStyle.ForeColor If (cellState And _ DataGridViewElementStates.Selected) = _ DataGridViewElementStates.Selected Then textColor = parent.InheritedStyle.SelectionForeColor End If [C#] Color textColor = parent.InheritedStyle.ForeColor; if ((cellState & DataGridViewElementStates.Selected) == DataGridViewElementStates.Selected) { textColor = parent.InheritedStyle.SelectionForeColor; }

Note that the cellState parameter can contain multiple values, combined together—you must use the And operator, as shown here, to determine if any single value is set within the parameter.)

Finally, the code draws the text at the correct location within the cell:

[Visual Basic] Using brush As New SolidBrush(textColor) graphics.DrawString(cellText, fnt, brush, _ cellBounds.X + textStart.X, _ cellBounds.Y + textStart.Y) End Using [C#] using (SolidBrush brush = new SolidBrush(textColor)) { graphics.DrawString(cellText, fnt, brush, cellBounds.X + textStart.X, cellBounds.Y + textStart.Y); }



Comment and Contribute

 

 

 

 

 


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

 

 

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