Headers in Wpf grid

This topic contains the following sections.

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 Copy imageCopy
<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# Copy imageCopy
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# Copy imageCopy
//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..::..Index, Column..::..VisibleIndex. The column may also be moved to any position in header using programming means:

C# Copy imageCopy
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 a Column.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# Copy imageCopy
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# Copy imageCopy
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# Copy imageCopy
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# Copy imageCopy
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# Copy imageCopy
//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 Copy imageCopy
<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# Copy imageCopy
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); 
    } 
}