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:

data binding 8
//The author
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; }
}


//The book
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:

<!--Declaration of the grid-->
<df:GridControl x:Name="grid" >
<df:GridControl.Headers>
<!--Top-level header-->
<df:Header ScrollType="Stretch">
<df:Header.Columns>
<df:Column Id="Name" Title="Name" CellHorizontalAlignment="Left" />
</df:Header.Columns>
</df:Header>
<!--Child invisible 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)
{
//Populate binding list with some authors
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);

//Bind grid to author collection
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; }

...
}
data binding 9

Now let’s review a case when an author writes a new book that should be added to the collection.

//Add a book to a 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;
}

...
}
data binding 10

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:

//The author    
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)
{
//Populate binding list with some authors
BindingList<Author> authors = new BindingList<Author>();
Author author = new Author("Agata Kristi");
authors.Add(author);

//Add some books with variable number of fields
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);

//Bind grid to author collection
grid.ItemsSource = authors;
}
data binding 11

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;
data binding 12

Back to Wpf GridControl features