Introduction
This article shows a practical & simple way to implement Master-Detail pattern with hierarchical DataTemplate.
Background
Master-Detail is a frequently used pattern in computer science and information systems. Almost every data oriented project is using this pattern. The principle is very simple, showing list of details by selected master item:
We can implement Master-Detail in multiple ways to achieve this pattern, in my opinion the easiest way to do so in WPF is using DataTemplate.
Representing the Hierarchical Data
Every
Master-Detail pattern requires a data structure. As an example of a
hierarchical data-structure, I’ve chosen to use the following hypothetical
Hi-Tech company:
The
company is comprised of three departments:
- Management: CEO, CTO, VP.QA
- Development: CTO
and subordinates on the development team.
- QA: VP of
QA and subordinates on the QA team.
For this example, I've chosen to take the aspect of the departments, i.e. every row in the view is a different department:
Let's
look at the classes:
public class Employee
{
public Employee()
{
Subordinates = new List<Employee>();
}
public List<Employee> Subordinates { get; set; }
public string Name
{
get;
set;
}
public override string ToString()
{
return this.Name;
}
}
Each
employee includes “subordinates” which is a collection of employees.
public class Department : INotifyPropertyChanged
{
public Department()
{
Employees = new List<Employee>();
}
public List<Employee> Employees { get; set; }
protected int m_EmployeesSelectedIndex = 0;
public int EmployeesSelectedIndex
{
get
{
return m_EmployeesSelectedIndex;
}
set
{
m_EmployeesSelectedIndex = value;
NotifyPropertyChanged("Subordinates");
}
}
public List<Employee> Subordinates
{
get
{
List<Employee> res = null;
if (Employees.Count > 0)
{
res = Employees[EmployeesSelectedIndex].Subordinates;
}
return res;
}
}
public string Name
{
get;
set;
}
public override string ToString()
{
return this.Name;
}
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Every
department includes a collection of the employees working there.
The
Department class also contains the following members:
- EmployeesSelectedIndex
- Subordinates list
- NotifyPropertyChanged mechanism
All
of these are used for implementing the Master-Detail Logic, and will be explained
in the section "Master-Detail Logic" below.
Presenting the Data (UI):
For
the sake of simplicity, we are presenting the data inside an ItemsControl:
<!---->
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" MinWidth="320">
<TextBlock Width="130" Text="{Binding Name}"/>
<ComboBox Width="130" ItemsSource="{Binding Employees}" SelectedIndex="{Binding EmployeesSelectedIndex}" />
<ComboBox Width="130" ItemsSource="{Binding Subordinates}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So
what we are dealing with here is simply a DataTemplate with:
- TextBlock - For the department name.
- ComboBox - For
the departments’ employees’ names.
- ComboBox - For
the selected employee’s subordinates.
Please Notice: In the code sample attached for download, there are also headers, borders & other simple UI decorations for each data item, but the logic is the same.
It should look like this:
Master-Detail Logic:
We
need to connect the selection of a particular employee to that employee’s subordinates
list.
That is why the Department class contains:
- EmployeesSelectedIndex
- Subordinates list
- NotifyPropertyChanged mechanism
Let’s see how it works:
About the examples for download:
The examples for download are a bit more complicated:
Master-Detail Simple file also contains:
- Headers, borders & other simple UI decorations for each data item.
- Subordinates Selected-Index for default selection of the first index in the Subordinates Combo-Box.
- Subordinates Is-Enabled for disabling the Subordinates Combo-Box when there are no Items.
Master-Detail Advanced file also contains:
- all of the above (from the Simple example)
- Employee-Image & Subordinate-Image