Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

Data Table, Cells And Rows Merging Control (XTable)

4.73/5 (4 votes)
3 Mar 2016CPOL2 min read 10.5K   271  
WPF Control allows to create complex data table with cell merging, columns merging, complex columns and rows merging

Introduction

While I am creating my custom applications, usually I need to show my data well formed, and want to merge cells and rows, and create a multi-level column header. I may use the builtin WPF controls like DataGrid or GridView but sometimes they are not helpful especially in the printing controls. In StackOverflow and on CodeProject, I searched for many days, but I couldn't find helpful things. In this tip, I am trying to solve this problem.

Using the Code

The XTable library contains the following controls:

  • XTableCell
  • XTableColumn
  • XTableRow
  • XTable

Firstly, the XTable is used as any WPF control:

XML
<XTable x:Name="table" />

You can customize the XTable with the provided properties:

XML
<XTable x:Name="table"
        RowHeight="30"
        VerticalAlignment="Top"
        MaxWidth="800"
        BorderBrush="Black"
        LinesBrush="Black"
        HeaderHeight="35"
        Margin="50"/>

Secondly, you should define the Columns:

XML
<XTable x:Name="table"
  RowHeight="30"
          VerticalAlignment="Top"
          MaxWidth="800"
          BorderBrush="Black"
  LinesBrush="Black"
  HeaderHeight="35"
          Margin="50"> 
<XTable.Columns>
                <XTableColumn Header="Manufacture" 
		Binding="{Binding Manufacture,
		UpdateSourceTrigger=PropertyChanged}" IsGrouped="True" /> 
</XTable.Columns>
</XTable>

and you can play with Columns Definitions which looks like:

XML
<XTable x:Name="table" RowHeight="30"
                           VerticalAlignment="Top"
                  MaxWidth="800"
                  BorderThickness="1 1 1 0"
                           BorderBrush="Black"
                           LinesBrush="Black" HeaderHeight="35"
                            Margin="50">
          <XTable.HeaderCellStyle>
              <Style TargetType="{x:Type XTableCell}">
                  <Setter Property="Background" Value="#FFF0EAEA" />
                  <Setter Property="FontFamily" Value="Tohama" />
                  <Setter Property="FontWeight" Value="Bold" />
              </Style>
          </XTable.HeaderCellStyle>
          <XTable.Columns>
              <XTableColumn Header="Manufacture"
      Binding="{Binding Manufacture,
      UpdateSourceTrigger=PropertyChanged}" IsGrouped="True" />
              <XTableColumn Header="Name"
      Binding="{Binding Name,UpdateSourceTrigger=PropertyChanged}" IsGrouped="True" />
              <XTableColumn Header="RAM"
      Binding="{Binding RAM,UpdateSourceTrigger=PropertyChanged, StringFormat={}{0:N2}}"
      IsGrouped="True" IsTransitive="True">
                  <XTableColumn.ContentTemplate>
                      <DataTemplate>
                          <TextBlock Text="{Binding .,StringFormat={}{0} MB}" />
                      </DataTemplate>
                  </XTableColumn.ContentTemplate>
              </XTableColumn>
              <XTableColumn Header="CPU"
          Binding="{Binding CPU,UpdateSourceTrigger=PropertyChanged}" />
              <XTableColumn Header="Price"
          Binding="{Binding Price,UpdateSourceTrigger=PropertyChanged}">
                  <XTableColumn.CellStyle>
                      <Style TargetType="{x:Type XTableCell}">
                          <Setter Property="Background" Value="LightYellow" />
                          <Setter Property="FontFamily" Value="Segoe UI Light" />
                          <Setter Property="ContentTemplate">
                              <Setter.Value>
                                  <DataTemplate>
                                      <TextBlock Text="{Binding .,StringFormat={}{0:N2} DZ}" />
                                  </DataTemplate>
                              </Setter.Value>
                          </Setter>
                      </Style>
                  </XTableColumn.CellStyle>
              </XTableColumn>
          </XTable.Columns>
      </XTable>

You ask about two properties of `XTableColumn`; `IsGrouping` and `IsTransitive` - I will answer your question:

  • IsGrouping: allows the cell merging in this column definition
  • IsTransitive: indicates if the column merging refers to the previous cell or no, for example in our model:
C#
public class Laptop
  {
      public string Manufacture { get; set; }
      public string Name { get; set; }
      public double RAM { get; set; }
      public string CPU { get; set; }
      public double Price { get; set; }
  }

and by using the XTable defined above, I got this result:

XTable

Suppose the laptop Dell, Inspiron 1525 and Dell, Studio 1535 have the same CPU and different RAM and we mark the CPU column IsGrouping True and IsTransitive False, do not forget the two laptops have the same manufacturer, so we can have cell merging in this case because the RAMs are distinct in others hence if IsTranstive turned to True, we can see the cell merging in the CPU cell.

IsTransitive takes care of the parent grouping cell, in some cases two rows having the same value in a cell but they are not in the same row, and they are neighbors.

The XTable has `ItemsSource` property. You can bind it or set it in code behind:

C#
table.ItemsSource = DataProvider.GetLaptops();

You can find the Open Source project at Github:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)