GridControl tutorial part7: Headers and columns

In Wpf grid headers are used for storing columns that can be used to manage content display and grouping and to display content with different presentations on different hierarchy levels.

There can be one or more headers, and therefore the grid can operate either in TreeList mode like Windows Explorer or as a fully functional grid with multiple independent headers.

A grid with a single header.

A grid with multiple headers.

Headers and columns

A header is a collection of columns that define content presentation in a grid on the relevant hierarchy level.

Header columns are added both in XAML and in C# or VB code.

XAML 
<df:Header> 
<df:Header.Columns>
<df:Column Id="Id0" Title="Column 0"/>
<df:Column Id="Id1" Title="Column 1"/>
<df:Column Id="Id2" Title="Column 2"/>
</df:Header.Columns>
</df:Header>

C# 

Header header = new Header(); 
header.Add(new Column("Id0", "Column 0"));
header.Add(new Column("Id1", "Column 1"));
header.Add(new Column("Id2", "Column 2"));

The header provides several convenient accessories to control and manage sequence, column visibility and data grouping. The following code demonstrates a way of receiving all header columns (both visible and invisible).

C# 
//Some code here... 
Header header = ...;

//Enumerate all columns in header
foreach (Column column in header.Columns)
{
//Some code here...
}

//Enumerate all grouped columns
foreach (Column column in header.GroupedColumns)
{ //Some code here...
}

//Enumerate all sorted columns
foreach (Column column in header.SortedColumns)
{
//Some code here...
}

//Find a column by its identifier or position:
Column column1 = header["MyColumn"];

Column column2 = header[5];

The column provides the following properties to establish column position in the header: Column.IndexColumn.VisibleIndex. The column may also be moved to any position in header using programming means:

C# 
Column column = header["MyColumn"]; 
column.VisibleIndex = 5;
Column sorting

A header is responsible for column sorting. Column sorting is set with Column.SortDirection property. Sorting direction is defined by SortDirection. Sequence of multiple sorting depends on sorting level. To understand sorting level of a column, one should just call aColumn.SortLevel property. A list of all sorted columns can be obtained with Header.SortedColumns. An example of most frequent usage of sorting in a grid is shown below.

C# 
Header header = ...; 
Column column1 = header["Column1"];
Column column2 = header["Column2"];

//Sort by the first column
column1.SortDirection = SortDirection.Ascending;

//Turn on the multiple sort by the second column
column2.SortDirection = SortDirection.Descending;

Debug.Assert(header.SortedColumns[0].Id == "Column1");
Debug.Assert(header.SortedColumns[1].Id == "Column2");
Debug.Assert(column1.SortLevel == 0);
Debug.Assert(column2.SortLevel == 1);
Debug.Assert(header.SortedColumns.Count == 2);

//Enumerate all sorted columns
foreach (Column column in header.SortedColumns)
{
//Some code here...
}

//Clear sort
header.SortedColumns.Clear();

Column grouping

The Header class can be used to group content by one or multiple columns. Since a grid may have multiple headers, grouping can be done on multiple hierarchy levels simultaneously.

To group data by one column, one has to set Column.Grouped property to true. Multiple grouping of data by various columns can be implemented by sequential setting of this property for such columns. Grouping is visually represented on the group panel, where columns can be dragged by user from the column panel. Height of this panel can be adjusted with Header.GroupPanelHeight property.

Most frequent methods of working with data grouping are shown below:

C# 
Header header = ...; 

Column column1 = header["Column1"];
Column column2 = header["Column2"];
column1.Grouped = true;

//Group the content by the first column
column1.Grouped = true;

//Turn on multiple grouping
column2.Grouped = true;
Debug.Assert(header.GroupedColumns[0].Id == "Column1");
Debug.Assert(header.GroupedColumns[1].Id == "Column2");
Debug.Assert(column1.GroupIndex == 0);
Debug.Assert(column2.GroupIndex == 1);
Debug.Assert(header.GroupedColumns.Count == 2);

//Enumerate all grouped columns
foreach (Column column in header.GroupedColumns)
{
//Some code here...
}

//Ungroup the content
header.GroupedColumns.Clear();
Column visibility and sequence

A programmer may also set column visibility and position. To define a manage visibility columns have Column.Visible property. Column visibility covers only the column panel. It is also possible to group data by hidden columns. Moreover, columns that are used for grouping are usually not displayed. An example of managing column visibility via API is shown below:

C# 
Header header = new Header(); 
header.Columns.Add(new Column("Column1"));
header.Columns.Add(new Column("Column2"));

Debug.Assert(header[0].Id == "Column1");
Debug.Assert(header[1].Id == "Column2");
Debug.Assert(header.VisibleColumns[0].Id == "Column1");
Debug.Assert(header.VisibleColumns[1].Id == "Column2");
Debug.Assert(header["Column1"].VisibleIndex == 0);
Debug.Assert(header["Column2"].VisibleIndex == 1);

//Hide the first column
header["Column1"].Visible = false;

//The header has the single visible column
Debug.Assert(header.VisibleColumns.Count == 1);
Debug.Assert(header.VisibleColumns[0].Id == "Column2");
Debug.Assert(header["Column2"].VisibleIndex == 0);

//Enumerate all visible columns
foreach (Column column in header.VisibleColumns)
{
//Some code here...
}

//Hide all columns
header.VisibleColumns.Clear();

Moving columns (i.e. changing positions of visible columns) is also a trivial task. An example of moving a visible column to header beginning or end is shown below:

C# 
Header header = ...; 

Column column = header["Column1"];

//Move the column to the beginning
column.VisibleIndex = 0;

//Move the column to the end
column.VisibleIndex = header.VisibleColumns.Count - 1;
Headers and hierarchy

Method of hierarchy presentation and grid behavior depends on the number of headers. If there is only one header, the grid behaves like Windows Explorer. If there are multiple headers, each hierarchy level may be controlled independently of other hierarchy levels. This is also true for data sorting and grouping.

In some cases, the number of headers may be lower than set in content. Header hierarchy level is determined by Header.Level property. Hierarchy level of a row grid is defined with Row.Level property. If hierarchy level of a row is higher than header level, the grid seeks a header of a previous hierarchy level. To make this more clear, let's review an example of a grid with two headers and three hierarchy levels.

C# 
//Add a top-level header 
Header header1 = new Header();

header1.Columns.Add(new Column("Name"));
header1.Columns.Add(new Column("Description"));
grid.Headers.Add(header1);

//Add a child header
Header header2 = new Header();
header2.Columns.Add(new Column("Name"));
header2.Columns.Add(new Column("Id"));
grid.Headers.Add(header2);

//Add data on the top hierarchical level
Row rowProduct = grid.Rows.Add(new Product());

//Add some data on the second level:
Row rowStrategy = rowProduct.Add(new Strategy());

//Add orders on the third level:
rowStrategy.Add(new Order());
rowStrategy.Add(new Order());

An image illustrating the above code is shown below:

Header declaration

Headers can be set both in XAML and in C# or VB code.

XAML 
<Window x:Class="TestApplication.Window1" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:df="clr-namespace:Dapfor.Wpf.Controls;assembly=Dapfor.Wpf"
Title="Dapfor WpfGrid" Height="427" Width="724">

<df:GridControl Name="grid" >
<df:GridControl.Headers>
<!-- Top-level header -->
<df:Header>
<df:Header.Columns>
<df:Column Id="Field1" Title="Column 1" Width="100" />
<df:Column Id="Field2" Title="Column 2" Width="100" />
</df:Header.Columns>
</df:Header>

<!-- Child header -->
<df:Header>
<df:Header.Columns>
<df:Column Id="Field3" Title="Column 3" Width="100" />
<df:Column Id="Field4" Title="Column 4" Width="100" />
</df:Header.Columns>
</df:Header>
</df:GridControl.Headers>
</df:GridControl>
</Window>

The same example in C# is shown below:

C# 
public partial class Window1 : Window 
{
public Window1()
{
InitializeComponent();

//Top-level header
Header header = new Header();
header.Columns.Add(new Column("Field1", "Column 1", 100));
header.Columns.Add(new Column("Field2", "Column 2", 100));
grid.Headers.Add(header);

//Child header
header = new Header();
header.Columns.Add(new Column("Field3", "Column 3", 100));
header.Columns.Add(new Column("Field4", "Column 4", 100));
grid.Headers.Add(header);
}
}

Back to Wpf GridControl tutorial