GridControl: Declarative hierarchical binding
Wpf GridControl can work with various data sources including hierarchical. At the same time, IBindingList doesn’t contain hierarchy information. After deep analysis of numerous applications we concluded that data objects may contain hierarchical information by themselves. There are a lot of such examples, i.e. various numbers of articles or books by an author, lists of department employees, financial indexes (e.g. CAC40 containing 40 largest French enterprises), etc. Therefore, this information may already be contained in the application business layer. For example, author-books relation can be expressed as follows:
class Author
{
public Author(string name)
{
Books = new List<Book>();
Name = name;
}
public IList<Book> Books { get; private set; }
public string Name { get; private set; }
}
class Book
{
public Book(Author author, string name)
{
Author = author;
Title = name;
}
public Author Author { get; private set; }
public string Title { get; private set; }
}
Let's declare a grid with two headers. The second one will be invisible:
<df:GridControl x:Name="grid" >
<df:GridControl.Headers>
<df:Header ScrollType="Stretch">
<df:Header.Columns>
<df:Column Id="Name" Title="Name" CellHorizontalAlignment="Left" />
</df:Header.Columns>
</df:Header>
<df:Header ScrollType="Stretch" Visible="False">
<df:Header.Columns>
<df:Column Id="Title" Title="Name" CellHorizontalAlignment="Left" />
</df:Header.Columns>
</df:Header>
</df:GridControl.Headers>
</df:GridControl>
A list of authors stored in IBindingList can be bound to the grid.
private void OnGridControl_Initialized(object sender, EventArgs e)
{
BindingList<Author> authors = new BindingList<Author>();
Author author = new Author("Agata Kristi");
author.Books.Add(new Book(author, "Second front"));
author.Books.Add(new Book(author, "Shameful Star"));
authors.Add(author);
author = new Author("Conan Doyle");
author.Books.Add(new Book(author, "The Blanched Soldier"));
author.Books.Add(new Book(author, "The Mazarin Stone"));
authors.Add(author);
grid.ItemsSource = authors;
}
However, hierarchy won’t be created as the grid has no information of author-books hierarchy structure. Dapfor’s framework provides an attribute to inform the grid about it by marking Author.Books as having a special attribute HierarchicalFieldAttribute for hierarchy building.
class Author
{
...
[HierarchicalField]
public IList<Book> Books { get; private set; }
...
}
Now let’s review a case when an author writes a new book that should be added to the collection.
author.Books.Add(new Book(author, "His Last Bow"));
Nothing happens, as the book collection is represented by List<Book> data type. If this collection is replaced with BindingList<Book>, the grid will get notifications of any changes in collection and automatically display them. The grid also checks whether sorting, filtering or grouping is required, i.e. whether the application has sufficiently complex behavior (grouping, sorting and filtering), while the developer needs to implement only a few simple classes.
class Author
{
public Author(string name)
{
Books = new BindingList<Book>();
Name = name;
}
...
}
The grid supports combinations of any data types. For example, instead of arbitrary class of Book type, it is possible to use Dictionary<string, object> or UnboundValueAccessor with variable number of fields:
class Author
{
public Author(string name)
{
Books = new BindingList<UnboundValueAccessor>();
Name = name;
}
[HierarchicalField]
public IList<UnboundValueAccessor> Books { get; private set; }
public string Name { get; private set; }
}
Let's populate the grid with authors:
private void grid_Initialized(object sender, EventArgs e)
{
BindingList<Author> authors = new BindingList<Author>();
Author author = new Author("Agata Kristi");
authors.Add(author);
UnboundValueAccessor book = new UnboundValueAccessor();
book["Title"].Value = "Second front";
book["Genre"].Value = "Detective story";
author.Books.Add(book);
book = new UnboundValueAccessor();
book["Title"].Value = "Shameful Star";
book["Genre"].Value = "Detective story";
author.Books.Add(book);
author = new Author("Conan Doyle");
authors.Add(author);
grid.ItemsSource = authors;
}
Finally, data can be added to the grid in multiple ways:
grid.Rows.Add(...);
grid.ItemsSource = ...;
or at any available hierarchy level, e.g., like this:
Row row = grid.Rows.Add(new object[] { "Detective stories" });
row.ItemsSource = authors;
Back to Wpf GridControl features