This sample demonstrates covered ranges, bannered ranges, and drawing background images.
Features:
Covered Range:
Covered ranges are cells that span multiple columns and rows.
Bannered ranges are cells that let you span only the background of a single cell across multiple columns and rows.
This sample also demonstrates the customization of a grid appearance through events at run time.
Customize the drawing of a cell's background at run-time with the TableControlDrawCellBackground event.
Customize style information of individual cells at run time with the TableControlPrepareViewStyleInfo event.
Covered ranges can be specified at run time by subscribing to the QueryCoveredRange event.
This event is raised for each cell when the grid renders the current visible cells.
In this event, you can allocate the number of rows and columns that a covered range should span.
Check whether the queried row is a record and if it has a parent group.
Also check to see if the column of the cell is a picture. In which case, you can get the number of rows in the group and return a range covering all rows in the column.
Bannered Range:
Bannered ranges can be specified at run time by subscribing to the QueryBanneredRange event.
This event is raised for each cell when the grid renders current visible cells.
In this event, you can allocate the number of rows and columns that a bannered range should span.
In the method given below, you can check whether the queried row is a record and has a parent group.
Also check whether the column of the cell is ProductName, in which case, you can get the number of rows in the group and return a range that covers all rows in the column.
This example also demonstrates customizing the drawing of individual cells and drawing your own background image.
An event is called before the cell text and borders are drawn, allowing you to render a bitmap behind multiple cells.
Using the TableControlDrawCellBackground event handler, get the image value from the first record in the group and draw to the specified cell area.
This example also demonstrates the easy adjustment of style settings for individual cells at run time.
This event is called for each cell before the cell is drawn.
In the event handler, get the first record of the group and retrieve the category name.
The name is then assigned to the cell value of the indent cell, and also, the font, color, and other style settings for this call will change.
private void TableModel_QueryCoveredRange(object sender, GridQueryCoveredRangeEventArgs e) { GridTableModel model = (GridTableModel) sender; GridTable table = model.Table; if (e.RowIndex < table.DisplayElements.Count) { // Get the element displayed at the row. Element el = table.DisplayElements[e.RowIndex]; // Check if element is a record (could also be a column header or group caption ...). if (Element.IsRecord(el) && el.ParentGroup != null) { GridTableCellStyleInfo style = model[e.RowIndex, e.ColIndex]; GridTableCellStyleInfoIdentity id = style.TableCellIdentity; // The cell identity contains column information. We check if the column is ProductName. if (id.Column != null && id.Column.MappingName == Categories_Picture) { Group group = el.ParentGroup; // Grouped by Categories_CategoryName? - Do not cover cells if not grouped by Category... if (group != null && group.CategoryColumns.Count > 0 && group.CategoryColumns[0].Name == Categories_CategoryName) { int tablePos = table.DisplayElements.IndexOf(group); int firstRow = tablePos+1; int lastRow = tablePos+group.GetVisibleCount()-1; e.Range = GridRangeInfo.Cells(firstRow, e.ColIndex, lastRow, e.ColIndex); e.Handled = true; } } } } }
The cell contents are rendered in the TableControlCellDrawn event, which is omitted here. You can check the code in the example.
Bannered ranges can be specified at run time by subscribing to the QueryBanneredRange event. This event is raised for each cell at the time when the grid renders the current visible cells. In this event you can allocate the number of rows and columns that a bannered range should span. In the method given below, you can check whether the queried row is a record and if it has a parent group. You can also check whether the column of the cell is ProductName. In that case, you can get the number of rows in the group and return a range that covers all the rows in the column.
private void TableModel_QueryBanneredRange(object sender, GridQueryBanneredRangeEventArgs e) { GridTableModel model = (GridTableModel) sender; GridTable table = model.Table; // Get the element displayed at the row. Element el = table.DisplayElements[e.RowIndex]; // Check if element is a record (could also be a column header or group caption ...). if (Element.IsRecord(el) && el.ParentGroup != null) { GridTableCellStyleInfo style = model[e.RowIndex, e.ColIndex]; GridTableCellStyleInfoIdentity id = style.TableCellIdentity; // The cell identity contains column information. We check if the column is ProductName. if (id.Column != null && id.Column.MappingName == "ProductName") { Group group = el.ParentGroup; // Now we get the number of rows in the group and return a range that covers all rows in the column. if (group != null && group.CategoryColumns.Count > 0 && group.CategoryColumns[0].Name == Categories_CategoryName) { int tablePos = table.DisplayElements.IndexOf(group); int firstRow = tablePos+1; int lastRow = tablePos+group.GetVisibleCount()-1; e.Range = GridRangeInfo.Cells(firstRow, e.ColIndex, lastRow, e.ColIndex); e.Handled = true; } } } }
This example also shows you how to customize the drawing of individual cells and how to draw your own background image. The event is called before the cell text and borders are drawn. This allows you to render a bitmap behind multiple cells.
In the TableControlDrawCellBackground event handler, you can get the image value from the first record in the group and draw it to the specified cell area.
private void gridGroupingControl1_TableControlDrawCellBackground(object sender, GridTableControlDrawCellBackgroundEventArgs e) { GridTableCellStyleInfo style = (GridTableCellStyleInfo) e.Inner.Style; GridTableCellStyleInfoIdentity id = style.TableCellIdentity; // Categories_Picture column. if (id.Column != null && id.Column.MappingName == "ProductName") { Group group = id.DisplayElement.ParentGroup; // Grouped by Categories_CategoryName? - Do not draw if not grouped by Category... if (group != null && group.CategoryColumns.Count > 0 && group.CategoryColumns[0].Name == Categories_CategoryName) { if (group.Records.Count > 0) { // Get image from first Picture column in first record of the group Record r = group.Records[0]; object value = r.GetValue(Categories_Picture); // Should be byte[] (image stream ...). byte[] byteStream = value as byte[]; if (byteStream != null) { Graphics graphics = e.Inner.Graphics; Rectangle bounds = e.Inner.TargetBounds; bounds = GridMargins.RemoveMargins(bounds, style.TextMargins.ToMargins()); bounds = GridMargins.RemoveMargins(bounds, style.BorderMargins.ToMargins()); // Convert byte stream to image and draw it. Image image = GridImageUtil.ConvertToImage(byteStream); DrawBackgroundImage(graphics, image, bounds); e.Inner.Cancel = true; // signals you did your own drawing } } } } }
This example also demonstrates how you can easily adjust the style settings for individual cells at run time. If you look at the screenshot for the example, you will notice that the category name that is displayed is rotated vertically in the indent area of the group. This is achieved by handling the TableControlPrepareViewStyle event.
The event is called for each cell before the cell is drawn. In the event handler, you can get the first record of the group and retrieve the category name. The name is then assigned to the cell value of the indent cell, and also, the font, color, and other style settings are changed for this cell.
private void gridGroupingControl1_TableControlPrepareViewStyleInfo(object sender, GridTableControlPrepareViewStyleInfoEventArgs e) { GridTableCellStyleInfo style = (GridTableCellStyleInfo) e.Inner.Style; GridTableCellStyleInfoIdentity id = style.TableCellIdentity; // Cell identity contains information about the cell (element, column etc.,). // Check if this is a indent cell. if (id.TableCellType == GridTableCellType.GroupIndentCell) { Group group = id.DisplayElement.ParentGroup; // Check if this is the indent of a Categories_CategoryName group. if (group != null && group.CategoryColumns.Count > 0 && group.CategoryColumns[0].Name == Categories_CategoryName) { // And if the group is not empty ... if (group.Records.Count > 0) { // Get the category name from the first record. Record r = group.Records[0]; object value = r.GetValue(Categories_CategoryName) // Should be a string. string categoryName = value as string; // Assign the name to the 'CellValue' of the Indent cell and also adjust the font, color and other style settings. if (categoryName != null) { style.Interior = new BrushInfo(GradientStyle.Vertical, Color.FromArgb( 219, 226, 242 ), Color.FromArgb( 255, 187, 111 )); style.CellValue = categoryName; style.CellType = "Static"; style.HorizontalAlignment = GridHorizontalAlignment.Center; style.VerticalAlignment = GridVerticalAlignment.Middle; style.Trimming = StringTrimming.EllipsisCharacter; style.Font.Bold = true; style.Font.Italic = true; style.Font.Orientation = 270; } } } } }