Bind Custom Object List To Treeview Using MVVM In WPF

Objective

 
In this Article our objective is to display a list of person objects in treeview. We will provide a AddPerson button in UI. When we click on the AddPerson button, a new Item should add in List<Person> object and same should reflect in UI as shown below,
  • PersonName
    • Gender
    • Age
  • PersonName
    • Gender
    • Age
Before starting your project create 3 folders under your WPF new project like below and delete MainWinow.xaml class
 
Bind Custom Object List To Treeview Using MVVM In WPF
 
Create a Person class in Model Folder
  1. namespace TreeviewBindingAPP.Model  
  2. {  
  3.     public class Person  
  4.     {  
  5.        public string Name { getset; }  
  6.        public int Age { getset; }  
  7.        public string Gender { getset; }  
  8.     }  
  9. }  
Create PersonViewModel.cs Class in ViewModel folder and inherit INotifyPropertyChanged Interface and provide implantation as below.
  1. using System.Collections.Generic;  
  2. using System.ComponentModel;  
  3. using System.Windows.Input;  
  4. using TreeviewBindingAPP.Commands;  
  5. using TreeviewBindingAPP.Model;  
  6.   
  7. namespace TreeviewBindingAPP.ViewModel  
  8. {  
  9.     public class PersonViewModel : INotifyPropertyChanged  
  10.     {  
  11.         public event PropertyChangedEventHandler PropertyChanged;  
  12.   
  13.         public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propertyName));  
  14.   
  15.         private List<Person> _persons;  
  16.         public List<Person> Persons  
  17.         {  
  18.             get => _persons;  
  19.             set  
  20.             {  
  21.                 _persons = value;  
  22.                 OnPropertyChanged(nameof(Persons));  
  23.             }  
  24.         }  
  25.   
  26.         private ICommand command;  
  27.         public ICommand ActionCommand  
  28.         {  
  29.             get => command ?? new RelayCommand(this);  
  30.         }  
  31.     }  
  32. }  
Create RelayCommand class in Commands folder and inherit ICommand Interface and provide implementation as shown below
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Windows.Input;  
  5. using TreeviewBindingAPP.Model;  
  6. using TreeviewBindingAPP.ViewModel;  
  7.   
  8. namespace TreeviewBindingAPP.Commands  
  9. {  
  10.     public class RelayCommand : ICommand  
  11.     {  
  12.         PersonViewModel _personViewModel;  
  13.   
  14.         public RelayCommand(PersonViewModel personViewModel)  
  15.         {  
  16.             _personViewModel = personViewModel;  
  17.         }  
  18.           
  19.         public event EventHandler CanExecuteChanged;  
  20.   
  21.         public bool CanExecute(object parameter) => true;  
  22.   
  23.         public void Execute(object parameter)  
  24.         {  
  25.             if (parameter is null)  
  26.                 return;  
  27.   
  28.             string action = parameter.ToString();  
  29.             switch(action)  
  30.             {  
  31.                 case "AddPerson":  
  32.                     AddPersons();  
  33.                     break;  
  34.             }  
  35.         }  
  36.   
  37.         private void AddPersons()  
  38.         {  
  39.             if (_personViewModel.Persons is null)  
  40.                 _personViewModel.Persons = new List<Person>();  
  41.   
  42.             var temp = _personViewModel.Persons;  
  43.             _personViewModel.Persons = new List<Person>();  
  44.   
  45.             temp.Add(new Person  
  46.             {  
  47.                 Name = "ABC_" + temp.Count() + 1,  
  48.                 Age = int.Parse(DateTime.Now.ToString("ss")),  
  49.                 Gender = "Male"  
  50.             });  
  51.             _personViewModel.Persons = temp;  
  52.         }  
  53.     }  
  54. }  
Create PersonView.xaml window in View folder and provide implementation in XAML as shown below and In App.xaml file update StartupUri as StartupUri="View/PersonView.xaml" 
  1. <Window x:Class="TreeviewBindingAPP.View.PersonView"  
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  6.         xmlns:viemModel="clr-namespace:TreeviewBindingAPP.ViewModel" BorderBrush="Black" BorderThickness="1"  
  7.         mc:Ignorable="d" SizeToContent="WidthAndHeight" WindowStyle="None" AllowsTransparency="True" MouseDown="Window_MouseDown"   
  8.         Title="PersonView" MinHeight="600" MinWidth="800">  
  9.     <Window.DataContext>  
  10.         <viemModel:PersonViewModel/>  
  11.     </Window.DataContext>  
  12.     <Grid>  
  13.         <Grid.RowDefinitions>  
  14.             <RowDefinition Height="30"/>  
  15.             <RowDefinition Height="80*"/>  
  16.             <RowDefinition Height="30"/>  
  17.         </Grid.RowDefinitions>  
  18.   
  19.         <Grid Grid.Row="0" Background="Orange">  
  20.             <Label Content="Bind Custom object List to Treeview" FontSize="14" Foreground="White" FontWeight="SemiBold"/>  
  21.             <Button Height="24" Width="24" Name="btnClose" HorizontalAlignment="Right" FontWeight="Bold" Cursor="Hand"  
  22.                     VerticalAlignment="Center" Content="X" Click="BtnClose_Click" Focusable="False" Background="{x:Null}" Foreground="White" />  
  23.             <x:Code>  
  24.                 private void BtnClose_Click(object sender, RoutedEventArgs e)  
  25.                 {  
  26.                     Close();  
  27.                 }  
  28.                  private void Window_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)  
  29.                 {  
  30.                     try  
  31.                     {  
  32.                         this.DragMove();  
  33.                     }  
  34.                     catch   
  35.                     {  
  36.                     }  
  37.                 }  
  38.             </x:Code>  
  39.         </Grid>  
  40.         <Grid Grid.Row="1">  
  41.             <Grid.ColumnDefinitions>  
  42.                 <ColumnDefinition Width="20*"/>  
  43.                 <ColumnDefinition Width="80*"/>  
  44.             </Grid.ColumnDefinitions>  
  45.             <Grid Grid.Column="0">  
  46.                 <StackPanel Orientation="Horizontal">  
  47.                     <Grid Grid.Row="0" Background="White" >  
  48.                         <Button Name="AddPerson" Height="30" Width="200" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{x:Null}" Content="Add person" Command="{Binding ActionCommand}" CommandParameter="{Binding ElementName=AddPerson, Path=Name}"/>  
  49.                     </Grid>  
  50.                     <Grid Grid.Row="1" Margin="100,0,0,0" >  
  51.                         <TreeView  Height="600" Width="200" FontSize="24" FontFamily="Segoe UI" HorizontalAlignment="Right" VerticalAlignment="Top" ItemsSource="{Binding Persons}">  
  52.                             <TreeView.ItemTemplate>  
  53.                                 <HierarchicalDataTemplate>  
  54.                                     <TreeViewItem Header="{Binding Name}">  
  55.                                         <TreeViewItem Header="{Binding Gender}"/>  
  56.                                         <TreeViewItem Header="{Binding Age}"/>  
  57.                                     </TreeViewItem>  
  58.                                 </HierarchicalDataTemplate>  
  59.                             </TreeView.ItemTemplate>  
  60.                         </TreeView>  
  61.                     </Grid>  
  62.                 </StackPanel>  
  63.             </Grid>  
  64.         </Grid>  
  65.         <Grid Grid.Row="2" Background="DarkGray">  
  66.   
  67.         </Grid>  
  68.     </Grid>  
  69. </Window>  
In above code we can see code for Treeview (same code copied in below) 
  1. <TreeView  Height="600" Width="200" FontSize="24" FontFamily="Segoe UI" HorizontalAlignment="Right" VerticalAlignment="Top" ItemsSource="{Binding Persons}">  
  2.                             <TreeView.ItemTemplate>  
  3.                                 <HierarchicalDataTemplate>  
  4.                                     <TreeViewItem Header="{Binding Name}">  
  5.                                         <TreeViewItem Header="{Binding Gender}"/>  
  6.                                         <TreeViewItem Header="{Binding Age}"/>  
  7.                                     </TreeViewItem>  
  8.                                 </HierarchicalDataTemplate>  
  9.                             </TreeView.ItemTemplate>  
  10. </TreeView>   
For Treeview control we are setting TreeView.ItemTemplate.
 
ItemTemplate is used to get or set the date for every TreeViewItem. For now we need to display data in a hierarchical way so in ItemTemplate again we need to HierarchicalDataTemplate class. Under HierarchicalDataTemplate tag we can mention how we want to display the custom object. For instance in our example we want to display Person Name as Header Item and inside that we will show Age and Gender of the Header bound person; i.e., when Name TreeViewItem is expanded, In UI we can see the Age and Gender
 

How is object added into TreeView?

 
As per MVVM, ViewModel is bind to View using Window.DataContext.
 
List<Person> Persons is created in ViewModel and did binding to TreeView’s ItemSource in PersonView.xaml class.
 
We added a button in UI called AddPerson and its command is bound to ActionCommand, which is defined in PersonViewModel with type ICommand. This is responsible to pass action performed in UI to RelayCommand class as RelayCommand is inherited by ICommand. So when we click on Button, Button will notify ActionCommand and ActionCommand will notify RelayCommand to perform method AddPersons.The movement new object is added in Persons object and Persons object will notify to UI as we already bound the Persons Object in xaml class and reflect in TreeView
 
Below is the execution window snap,
 
Bind Custom Object List To Treeview Using MVVM In WPF
 

Summary

 
In this article welearned how to bind the custom list object to treeview and use of ItemTemplate and HierarchicalDataTemplate.