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
C# Copy imageCopy
//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:

XAML Copy imageCopy
<!--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.

C# Copy imageCopy
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.

C# Copy imageCopy
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.

C# Copy imageCopy
//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.

C# Copy imageCopy
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:

 Copy imageCopy
//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:

C# Copy imageCopy
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:

 Copy imageCopy
grid.Rows.Add(...);
grid.ItemsSource = ...;

or at any available hierarchy level, e.g., like this:

 Copy imageCopy
Row row = grid.Rows.Add(new object[] { "Detective stories" });
row.ItemsSource = authors;
data binding 12