Use the Custom Draw Events to Customize the Appearance of Spreadsheet Elements
- 13 minutes to read
The WinForms Spreadsheet control supports custom draw events that allow you to customize the appearance of worksheet cells, column headers, and rows headers. You can display custom text, change background settings, or draw images and geometric primitives (lines, rectangles, callouts, and so on) over these elements.
Custom Draw Scenarios
The following custom draw scenarios are supported:
- Custom Painting
- Custom draw events fire before the Spreadsheet control renders its elements with the default appearance settings. Enable the CustomDrawObjectEventsArgs.Handled property in the event handler to cancel default painting and draw an element manually. If this property is false, the Spreadsheet control can override custom appearance settings.
- Combined Painting
- You can combine custom and default painting. Call the CustomDrawObjectEventsArgs.DrawDefault method in the custom draw event handler to invoke the default drawing mechanism to display a spreadsheet element. Then set the CustomDrawObjectEventsArgs.Handled property to true and add custom graphics to the element.
- Default Painting with Custom Settings
- Data classes of the custom draw events contain properties that allow you to customize the default appearance settings for a spreadsheet element (such as background color, foreground color, or font attributes). If you use these properties to change the element’s appearance, you do not need to enable the CustomDrawObjectEventsArgs.Handled property. The default drawing mechanism takes these property values into account when it renders the element.
Important
You can use custom painting to change the Spreadsheet control’s visual appearance only. All your custom appearance settings are ignored when you print or export spreadsheet content to PDF.
Custom Paint Cells
Customize Cell Content
The SpreadsheetControl.CustomDrawCell event fires for each cell in the visible worksheet area and allows you to customize cell content. Use properties of the event data class (CustomDrawCellEventArgs) to access a cell to paint, obtain cell bounds, change cell text, specify font attributes, and display custom graphics over the cell.
The code snippet below uses the SpreadsheetControl.CustomDrawCell event to display images for product categories and add callouts to cells that contain 0 in the “Units In Stock” column. The Spreadsheet control uses the default drawing mechanism to render these cells and then displays custom graphics over cells.
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawCell(object sender, CustomDrawCellEventArgs e)
{
// Check whether a cell belongs to the "Category" column.
if (e.Cell.ColumnIndex == 1) {
// Obtain the category name.
String categoryName = e.Cell.Value.ToString();
// Return the image that corresponds to the category name.
Image categoryImage = ChooseImage(categoryName);
// Specify the image location (the upper-right corner of the cell).
Point point = new Point(e.Bounds.Right - 50, e.Bounds.Top);
// Draw the category image over the cell.
if (categoryImage != null)
e.Graphics.DrawImage(categoryImage, point);
}
// If a cell belongs to the "Units In Stock" column and the cell value is "0",
// draw a callout to the right of this cell.
if (e.Cell.ColumnIndex == 4 && e.Cell.Value.IsNumeric && e.Cell.Value.NumericValue == 0)
{
// Specify callout text.
string text = "OUT OF STOCK";
using (Font font = new Font(e.Font.Name, 9f, FontStyle.Bold))
{
using (StringFormat format = new StringFormat())
{
// Align callout text.
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
// Calculate the callout bounds.
SizeF size = e.Graphics.MeasureString(text, font, int.MaxValue, format);
Rectangle textBounds = new Rectangle(
e.Bounds.Right + 15,
(int)Math.Round(e.Bounds.Top + (e.Bounds.Height - size.Height) / 2),
(int)(size.Width + 8),
(int)Math.Round(size.Height));
int middle = (int)Math.Round(textBounds.Height / 2.0);
Point[] points = new Point[] {
new Point(textBounds.Left, textBounds.Top),
new Point(textBounds.Left - middle, textBounds.Top + middle),
new Point(textBounds.Left, textBounds.Bottom)
};
// Draw the callout.
Brush brush = e.Cache.GetSolidBrush(Color.FromArgb(200, 44, 74));
e.Graphics.FillPolygon(brush, points);
e.Cache.FillRectangle(brush, textBounds);
e.Graphics.DrawString(text, font, e.Cache.GetSolidBrush(Color.White), textBounds, format);
}
}
}
}
private Image ChooseImage(string categoryName)
{
switch (categoryName)
{
case "Beverages":
return Image.FromFile("images/beverages.png");
case "Condiments":
return Image.FromFile("images/condiments.png");
case "Confections":
return Image.FromFile("images/confections.png");
case "Dairy Products":
return Image.FromFile("images/dairy.png");
case "Grains/Cereals":
return Image.FromFile("images/cereals.png");
case "Meat/Poultry":
return Image.FromFile("images/meat.png");
case "Produce":
return Image.FromFile("images/produce.png");
case "Seafood":
return Image.FromFile("images/seafood.png");
}
return null;
}
Customize Cell Background
The SpreadsheetControl.CustomDrawCellBackground event fires for each cell in the visible worksheet area and allows you to customize the cell background. This event receives a CustomDrawCellBackgroundEventArgs object as a parameter. The object’s properties allow you to access a cell to paint, obtain cell bounds, and specify appearance settings for the cell background.
The following code example changes background color for the active cell and cells in odd rows. The Spreadsheet control uses the default drawing mechanism to paint cells with the custom background.
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawCellBackground(object sender,
CustomDrawCellBackgroundEventArgs e)
{
// Specify the background color for the active cell.
if (e.Cell == spreadsheetControl1.ActiveCell)
{
e.BackColor = Color.FromArgb(50, 200, 44, 74);
return;
}
// Specify the background color for cells that contain data and belong to odd rows.
var dataRange = e.Cell.Worksheet.GetDataRange();
if (e.Cell.IsIntersecting(dataRange) && e.Cell.RowIndex % 2 != 0)
{
e.BackColor = Color.FromArgb(50, 91, 155, 213);
}
}
Custom Paint Column Headers
Customize Column Header Content
The SpreadsheetControl.CustomDrawColumnHeader event fires before a column header is painted and allows you to customize column header content. Use properties of the event data class (CustomDrawColumnHeaderEventArgs) to access a column header to paint, obtain its bounds, change header text, specify font attributes, or display geometric primitives and images.
The code snippet below handles the SpreadsheetControl.CustomDrawColumnHeader event to change default text (A, B, C, …) in column headers. This example does not change the background color of column headers. Refer to the next section in this topic for information on how to apply a custom color to column headers.
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawColumnHeader(object sender,
CustomDrawColumnHeaderEventArgs e)
{
// Cancel default painting for the column header.
e.Handled = true;
if (e.ColumnIndex > 4)
return;
// Specify the list of new column header names.
string[] headers = new string[] { "Category", "Product Name",
"Quantity per Unit", "Unit Price", "Units in Stock" };
// Specify font attributes for the column header.
SpreadsheetFont defaultFont = spreadsheetControl1.Document.Styles.DefaultStyle.Font;
using (Font font = new Font(defaultFont.Name, (float)defaultFont.Size, FontStyle.Bold))
{
// Specify layout settings for the column header.
using (StringFormat stringFormat = new StringFormat())
{
stringFormat.LineAlignment = StringAlignment.Center;
stringFormat.Alignment = e.ColumnIndex < 3 ? StringAlignment.Near : StringAlignment.Far;
stringFormat.Trimming = StringTrimming.EllipsisCharacter;
// Draw the column header.
e.Graphics.DrawString(headers[e.ColumnIndex], font,
e.Cache.GetSolidBrush(Color.White), e.Bounds, stringFormat);
}
}
}
Customize Column Header Background
The SpreadsheetControl.CustomDrawColumnHeaderBackground event fires before a column header is painted and allows you to customize the column header background. This event receives a CustomDrawColumnHeaderBackgroundEventArgs object as a parameter. The object’s properties allow you to access a column header to paint, obtain its bounds, and specify appearance settings for the header background.
The following code snippet demonstrates how to change the background color for column headers. This example applies a dark red color to a column header under the mouse pointer or if a header belongs to a column with the active cell:
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawColumnHeaderBackground(object sender,
CustomDrawColumnHeaderBackgroundEventArgs e)
{
// Cancel default painting for the column header background.
e.Handled = true;
// If the column header is under the mouse pointer or the column contains the active cell,
// paint the column header background in Color 1.
// Otherwise, use Color 2.
if (e.ColumnIndex <= 4) {
var backColor = e.IsHovered || (e.ColumnIndex == spreadsheetControl1.ActiveCell.ColumnIndex) ?
//Color 1
Color.FromArgb(200, 44, 74) :
//Color 2
Color.FromArgb(91, 155, 213);
e.Cache.FillRectangle(e.Cache.GetSolidBrush(backColor), e.Bounds);
}
}
Custom Paint Row Headers
Customize Row Header Content
The SpreadsheetControl.CustomDrawRowHeader event fires before a row header is painted and allows you to customize row header content. Use properties of the event data class (CustomDrawRowHeaderEventArgs) to access a row header to paint, obtain its bounds, change header text, specify font attributes, or display geometric primitives and images.
The code snippet below uses the SpreadsheetControl.CustomDrawRowHeader event to display a row number for every fifth row.
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawRowHeader(object sender, CustomDrawRowHeaderEventArgs e)
{
// Cancel default painting for the row header.
e.Handled = true;
// Display a row number for every fifth row.
if ((e.RowIndex + 1) % 5 == 0)
{
// Specify font style.
e.Appearance.FontStyleDelta = FontStyle.Bold;
// Return the row header bounds.
Rectangle textBounds = e.Bounds;
// Specify row header text.
string text = (e.RowIndex + 1).ToString();
// Specify text alignment.
StringFormat format = new StringFormat {
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center
};
// Draw row header text.
e.Graphics.DrawString(text, e.Font,
e.Cache.GetSolidBrush(Color.FromArgb(91, 155, 213)), textBounds, format);
}
}
Customize Row Header Background
The SpreadsheetControl.CustomDrawRowHeaderBackground event fires before a row header is painted and allows you to customize the row header background. This event receives a CustomDrawRowHeaderBackgroundEventArgs object as a parameter. The object’s properties allow you to access a row header to paint, obtain its bounds, and specify appearance settings for the header background.
The following code snippet demonstrates how to change the background color for row headers. This example applies a dark red color to a row header under the mouse pointer or if a header belongs to a row with the active cell:
using System;
using System.Drawing;
using DevExpress.Spreadsheet;
using DevExpress.XtraSpreadsheet;
// ...
private void spreadsheetControl1_CustomDrawRowHeaderBackground(object sender,
CustomDrawRowHeaderBackgroundEventArgs e)
{
// Cancel default painting for the row header background.
e.Handled = true;
// If the row header is under the mouse pointer or the row contains the active cell,
// paint the row header background in Color 1.
// Otherwise, paint the row header in white.
Color backColor = e.IsHovered || (e.RowIndex == spreadsheetControl1.ActiveCell.RowIndex) ?
Color.FromArgb(200, 44, 74) : // Color 1
Color.White;
e.Cache.FillRectangle(e.Cache.GetSolidBrush(backColor), e.Bounds);
}