A Grid consists of rows and columns of data that is displayed in a tabular format.
Each Column is sized automatically to fit its widest content.
In addition to the rows and columns, grids can also have a Title, Subtitle and Footer.
The titles are shown above the rows/columns, the footer is beneath the rows/columns.
The appearance and layout of the grid’s columns, rows, and cells can be customized through the use of properties available at the various levels. The styling for the titles and footer can also be customized.
Grid ClassTo create a grid, use the Grid class. Add columns and rows.
Then use the Show method to display the grid.
Columns can be added using any of the various AddColumn methods or the
grid’s Columns collection.
Rows can be added using any of the various AddRow methods or the grid’s
Rows collection.
There is also an AddSeparatorRow method that will add a
“separator” row to the grid. A separator row is just a normal row with
each cell’s FillerChar property set to the value of the fillerChar
argument, and each cell’s Content property set to null.
Styling for all the grid’s cells can be set via the CellStyle, and CellContentStyle properties.
These styles can be overridden at the column, row, and cell level.
Styling for all the grid’s column headers can be set via the ColumnHeaderCellStyle, and ColumnHeaderContentStyle properties.
These styles can be overridden for each column. Rendering of column headers can be
controlled via the ShowColumnHeaders property.
The Title, Subtitle and Footer properties are StyledText objects.
See the doc for the TextStyle and StyledText classes
for information on how to apply styling to these grid elements. Additionally, there are
alignment properties for each (TitleAlignment, SubtitleAlignment, FooterAlignment)
that control the horizontal alignment of the content.
Note: Calling the Show method if the grid does not have at least one column and one row will
result in an exception being thrown. After all, it is somewhat pointless to display a grid
without at least one of each.
The Grid class has a Find method that will perform a search of all the grid’s cells
and return a sequence containing the matching cells.
The find method takes a GridSearchExpression argument.
GridColumn ClassRepresents a column in a grid.
A column has a Header property that returns a GridHeaderCell object for its header cell.
The read-only Header property will always have a non-null value.
The various properties of the Header object can be used to control the content, appearance and layout
of the column’s header.
The column’s CellLayout property controls the layout for the column’s cells, including
the Header cell.
The styling for a column’s cells can be set through its CellStyle and ContentStyle properties.
Setting these styles will override the styles inherited from the grid.
A column always has a Cells collection, which always contains the same number of
GridCell objects as the grid’s Rows collection (even if zero).
The HasCells property returns a boolean indicating whether or not the column has any cells
(i.e. whether or not the grid has any rows). The Cells collection is readonly – to add rows
to a grid, use the Rows collection, or one of the AddRow methods of the Grid object.
The GridColumn class has Find, FindFirst, FindRows and FindFirstRow methods
that will perform a search of all the columns’s cells.
These methods take a GridSearchExpression argument and
return a sequence containing
the matching cells (Find)
or rows (FindRows),
the first matching cell (FindFirst),
or the first matching row (FindFirstRow).
GridColumns ClassThe GridColumns class represents a collection of GridColumn objects for a grid (Grid.Columns).
GridColumns implements the IReadOnlyList<GridColumn> interface and also includes IndexOf,
Add, Remove, and RemoveAt methods to allow limited manipulation of the collection.
If a column is added to the grid when it has rows, cells are automatically added to each
row’s Cells collection.
If a column is removed from the grid when it has rows, the corresponding cell is automatically
removed from each row’s Cells collection.
GridRow ClassRepresents a row in a grid.
A row always has a Cells collection, which always contains the same number of
GridCell objects as the grid’s Columns collection (even if zero).
The HasCells property returns a boolean indicating whether or not the row has any cells
(i.e. whether or not the grid has any columns).
If a column is added to the grid, cells are automatically added to each row.
If a column is removed from the grid, the corresponding cell is automatically removed from
each row.
The Cells collection is readonly – to add columns to a grid, use the Columns
collection, or one of the AddColumn methods of the Grid object.
The styling for a row’s cells can be set through its CellStyle and ContentStyle properties.
Setting these styles will override the styles inherited from the column or grid.
The GridRow class has Find, FindFirst, FindColumns and FindFirstColumn methods
that will perform a search of all the row’s cells.
These methods take a GridSearchExpression argument and
return a sequence containing
the matching cells (Find)
or columns (FindColumns),
the first matching cell (FindFirst),
or the first matching column (FindFirstColumn).
GridCell ClassThe content to be displayed in a given cell can be accessed via it’s (read/write)
Content property.
The Content property is a string value, so to display a value from any other type of
object, convert the value to a string. Empty string and null values are acceptable.
A null indicates the cell has no content, and an empty string is considered to be
“empty” content.
A cell has two types of text styling: cell styling and content styling.
Cell styling applies to the whole cell (i.e. the non-content area of the cell).
Content styling applies only to the cell’s content.
A cell’s text styling is inherited from its row, column or the grid (in that order),
however the styling can be overridden for an individual cell using the cell’s
CellStyle and ContentStyle properties.
A cell’s layout is inherited from the column (GridColumn.CellLayout).
The horizontal alignment of an individual cell can be overridden via the
cell’s HorizontalAlignment property. The cell’s other layout properties (margins, padding)
cannot be overridden.
A cell has readonly properties for Column, ColumnIndex, Row, and RowIndex.
These return information regarding the cell’s position within the grid.
Both the ColumnIndex and RowIndex properties are zero-based.
When a cell is rendered for display in the grid, the cell’s content is styled
using the cell’s ContentStyle (or the content style inherited from the
row, column or grid), and is padded with the number of characters specified
by the PaddingLeft, PaddingLeftChar, PaddingRight, and PaddingRightChar
properties of the column’s CellLayout. If the cell has NO content
(the cell’s Content property is null), the cell will contain NO padding
(the padding is considered Content padding, not cell padding).
The cell may additionally contain “filler” so that the cell’s width
meets the widest cell in the column. The character used for the cell’s filler
can be set via the FillerChar property. The cell is also padded with the
number of characters specified by the MarginLeft, MarginLeftChar,
MarginRight, and MarginRightChar properties of the column’s CellLayout.
Padding and “filler” are part of the cell and styled using the cell’s CellStyle
(or the cell style inherited from the row, column or grid).
Margins are NOT part of the cell, and no styling is applied to the margins.
There are a couple of extension methods that operate on a sequence of GridCell
objects.
The Find extension method operates on any collection (that implements IEnumerable)
of cells and takes a GridSearchExpression parameter. The cells can be any sequence of cells
from a grid, such as all the cells from a single row, or column, all the cells
from the grid, any subset of cells from a grid, row, column, or
any combination thereof. As with the Find methods for the grid, row or column,
it will return a sequence of matching cells.
The SetFillerChar extension method also operates on any collection of cells and
takes a char argument. The FillerChar property of each cell in the sequence
is set to the value of the char argument.
GridHeaderCell ClassA header cell contains the content and styling for a column header. The header for a column
can be accessed through the column’s Header property.
A header cell’s styling and layout work the same as a normal GridCell object.
Note: Since a header is not in a “row” of the grid, a header cell does NOT have a Row or RowIndex property.
GridCellLayout ClassAllows alignment, padding and margins to be specified for columns and cells.
When a grid cell is rendered, Padding is part of the cell, Margins are outside the cell.
GridSearchExpression ClassThe GridSearchExpression class represents a search expression that is used by
the Find methods for Grid, GridColumn, GridRow and the
IEnumerable<GridCell> extension.
The Text property specifies the text to search for. Both null and empty string are
acceptable, and search for cells containing those values, respectively.
The Type property (SearchType enum) specifies the type of search to perform.
The default is Equals.
The ComparisonType property (System.StringComparison) designates the comparison
type used for the search. The default is OrdinalIgnoreCase.
Grid g = new();
g.Title = new("Grid".SpaceOut());
g.Subtitle = new("Example 1");
g.Columns.Add("C 1");
g.Columns.Add("Column 2", HorizontalAlignment.Center);
g.Columns.Add("Col 3", HorizontalAlignment.Right);
g.AddRow("r1-c1", "row1-c2", "row1-column3");
g.AddRow("row2-column1", "row2-col2", "r2-col3");
g.AddRow("r3-col1", "row3-column2", "r3-c3");
g.Footer = new($"Total Count {g.RowCount}");
g.FooterAlignment = HorizontalAlignment.Left;
g.AddSeparatorRow('-');
g.Show();
RK();

Grid g = new();
g.Title = new("Grid".SpaceOut(), new TextStyle(Color.Silver, Color.Gray, Color.Silver) { BackColor = Color.LimeGreen, Reverse = true });
g.Subtitle = new("Example 2 (Styling)", Color.LimeGreen, Color.Gray);
//set cell/content styling for entire grid
g.CellStyle = new(Color.DodgerBlue, Color.Silver);
g.CellContentStyle = new(Color.Blue, Color.Silver);
g.ColumnHeaderContentStyle.Underline = false;
g.ColumnHeaderCellStyle.Underline = false;
GridColumn col = g.Columns.Add("C 1");
col.Header.HorizontalAlignment = HorizontalAlignment.Center; //override column header alignment
col = g.Columns.Add("Column 2", HorizontalAlignment.Center);
//override styling for column
col.CellStyle = new() { BackColor = Color.DarkGray };
g.Columns.Add("Col 3", HorizontalAlignment.Right);
g.AddRow("r1-c1", "row1-c2", "row1-column3");
GridRow row = g.AddRow("row2-column1", "row2-column2", "r2-col3");
//override styling for row
row.CellStyle = new(Color.White, Color.SlateGray);
row.ContentStyle = new(Color.White, Color.SlateGray);
//override styling for specific cell
GridCell cell = row.Cells[2];
cell.ContentStyle = new(Color.Red, Color.White);
cell.CellStyle = new(Color.White, Color.SlateGray);
g.AddRow("r3-col1", "row3-col2", "r3-c3");
g.Footer = new("Total Count 3", Color.White, Color.SkyBlue, Color.White);
g.Footer.Style.Reverse = true;
g.Show();
RK();

This example illustrates how cells are structured (including content, margins, padding, and filler) when a grid is rendered.
Color text = Color.White;
Color background = Color.FromArgb(64, 64, 64);
Grid grid = new Grid();
grid.ColumnHeaderContentStyle.BackColor = Color.Green;
grid.ColumnHeaderContentStyle.Underline = false;
grid.ColumnHeaderCellStyle.Underline = false;
grid.ColumnHeaderCellStyle.BackColor = Color.LightGreen;
grid.CellContentStyle.BackColor = Color.Silver;
grid.CellStyle.BackColor = Color.SkyBlue;
GridColumn col = grid.AddColumn();
col.CellLayout.PaddingLeft = 1;
col.CellLayout.PaddingLeftChar = 'p';
col.CellLayout.PaddingRight = 1;
col.CellLayout.PaddingRightChar = 'p';
col.Header.FillerChar = 'f';
GridRow row = grid.AddRow(" row 1 ");
row = grid.AddRow(" row 2 ");
row.Cells[0].HorizontalAlignment = HorizontalAlignment.Center;
row = grid.AddRow(" row 3 ");
row.Cells[0].HorizontalAlignment = HorizontalAlignment.Right;
grid.AddRow(""); //"empty" (zero-length) content -- will have padding
grid.AddRow(" ");
grid.AddRow(); //null (no content) -- no padding
grid.AddRow(" row 7 - wider ");
col.Header.Content = Ruler.GetH(col.ContentWidth, colors: null);
col.Cells.SetFillerChar('f');
CLS(background);
W(EscapeCodes.ColorReset_Back);
grid.Show();
int legendLeft = grid.Width + 2;
Console.SetCursorPosition(legendLeft, 0);
W("Legend", new TextStyle(Color.DodgerBlue, background) { Underline = true });
Console.SetCursorPosition(legendLeft, 1);
W(" ", text, Color.Black);
W(" Margin", text, background);
Console.SetCursorPosition(legendLeft, 2);
W("p Padding", text, background);
Console.SetCursorPosition(legendLeft, 3);
W("f Filler", text, background);
Console.SetCursorPosition(legendLeft, 4);
W(" ", text, grid.ColumnHeaderContentStyle.BackColor);
W(" Header content", text, background);
Console.SetCursorPosition(legendLeft, 5);
W(" ", text, grid.ColumnHeaderCellStyle.BackColor);
W(" Header non content", text, background);
Console.SetCursorPosition(legendLeft, 6);
W(" ", text, grid.CellContentStyle.BackColor);
W(" Cell content", text, background);
Console.SetCursorPosition(legendLeft, 7);
W(" ", text, grid.CellStyle.BackColor);
W(" Cell non content", text, background);
RK();
