Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How to: Use the Master-Detail Pattern with WPF Hierarchical DataTemplate

0.00/5 (No votes)
7 Apr 2014 1  
This article shows a simple way to implement Master-Detail pattern with hierarchical DataTemplate

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

    // This method is called by the Set accessor of each property. 
    // The CallerMemberName attribute that is applied to the optional propertyName 
    // parameter causes the property name of the caller to be substituted as an argument. 
    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:

  1. EmployeesSelectedIndex
  2. Subordinates list
  3. 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:

<!-- Data rows -->
<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:

  1. EmployeesSelectedIndex
  2. Subordinates list
  3. 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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here