GridControl: Declarative field joining

Continuing the idea of declarative data binding, Dapfor has implemented the concept of composite objects. As it has already been mentioned, it is recommended to use objects of arbitrary classes. Properties of these objects return values that are then displayed in corresponding grid cells. However, sometimes a class object doesn't have the required property but only refers to another object that contains the required information. There are a lot of such examples – a book written by some author or a stock quoted at a certain market. In both cases book or stock objects refer to other objects. However, when these objects are displayed in the grid, it is better to display not just object characteristics but some information taken from referenced objects.

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; }
}

As shown in the example, the book object provides information of publication date and name and has a reference to the author. If we have a binding list with books of different authors, it would be more convenient to see the author’s name in the grid in addition to book name and publication date.

private void OnGridControl_Initialized(object sender, EventArgs e)
{
BindingList<Book> books = new BindingList<Book>();

Author author = new Author("Agata Kristi");
books.Add(new Book(author, "Second front"));
books.Add(new Book(author, "Detective story"));

author = new Author("Conan Doyle");
books.Add(new Book(author, "The Blanched Soldier"));
books.Add(new Book(author, "The Mazarin Stone"));

grid.ItemsSource = books;
}

Without declarative binding this can be achieved by adding new fields to book class to return values received from Author object or by creating a new class combining properties of both objects and intended only for displaying in the grid. However, it is not a good solution. On the one hand, the code becomes bulky and contains duplicate information. On the other hand, the book object has properties that it shouldn‘t have. Besides, changing author class signature may cause problems as changes might also impact the book object. Declarative binding offered by Dapfor’s framework makes things different. Marking Book.Author field as a composite field makes the grid process it in a special way by combining Book and Author object fields. When a book is displayed, the grid calls Book.Author property but doesn’t display the Author object in a cell. When a header contains a column with FirstName identifier, the grid first searches Book object for this field and if it is not found, the grid searches the Author object. The business logic remains the same. There are different Author and Book objects, their fields are not duplicated and author data can be accessed by calling book.Author.FirstName. However, the grid displays data of both objects. It is possible to use any data type instead of Author (including data types with variable number of fields).

class Book
{
...

[CompositeField]
public Author Author { get; private set; }

...
}

If the book and the author have properties with the same names (e.g. Name), Author.Name property can be marked with FieldAttribute attribute for the purpose of displaying.

class Author
{
...

[Field("AuthorName")]
public string Name { get; private set; }
}

Let's prepare the grid to display authors with their books:

<!--Declaration of the grid-->
<df:GridControl Name="grid" >
<df:GridControl.Headers>
<df:Header ScrollType="Stretch">
<df:Header.Columns>
<df:Column Id="Title" Title="Title" CellHorizontalAlignment="Left" />
<df:Column Id="AuthorName" Title="Author" CellHorizontalAlignment="Left" />
</df:Header.Columns>
</df:Header>
</df:GridControl.Headers>
</df:GridControl>
data binding 13

Back to Wpf GridControl features