MVVM in WinUI TreeGrid (SfTreeGrid)
27 Feb 202524 minutes to read
This section explains various MVVM requirements using SfTreeGrid.
TreeGrid SelectedItem binding
You can bind the SelectedItem property directly to treegrid by setting the SfTreeGrid.SelectedItem
property.
<treeGrid:SfTreeGrid x:Name="sfTreeGrid"
ColumnWidthMode="Star"
AllowEditing="True"
AllowFiltering="True"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ChildPropertyName="Children"
AutoGenerateColumns="False"
ItemsSource="{Binding Employees}" />
Whenever the SelectedItem
is changed, the property in the view model will get notified.
public class ViewModel : NotificationObject
{
public ViewModel()
{
this.Employees = this.GetEmployees();
_selectedItem = Employees[1];
}
private ObservableCollection<Employee> _employees;
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set { _employees = value; RaisePropertyChanged("Employees"); }
}
private object _selectedItem;
public object SelectedItem
{
get { return _selectedItem; }
set { _selectedItem = value; RaisePropertyChanged("SelectedItem"); }
}
public static ObservableCollection<Employee> GetEmployees()
{
ObservableCollection<Employee> childCollection1 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection2 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection3 = new ObservableCollection<Employee>();
ObservableCollection<Employee> employeeList = new ObservableCollection<Employee>();
//Management
childCollection1.Add(new Employee() { FirstName = "Andrew", LastName = "Fuller", EmployeeID = 1001, Title = "Vice President" });
childCollection1.Add(new Employee() { FirstName = "Janet", LastName = "Leverling", EmployeeID = 1002, Title = "GM" });
childCollection1.Add(new Employee() { FirstName = "Steven", LastName = "Buchanan", EmployeeID = 1003, Title = "Manager" });
//Accounts
childCollection2.Add(new Employee() { FirstName = "Nancy", LastName = "Davolio", EmployeeID = 1004, Title = "Accounts Manager" });
childCollection2.Add(new Employee() { FirstName = "Margaret", LastName = "Peacock", EmployeeID = 1008, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Michael", LastName = "Suyama", EmployeeID = 1009, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Robert", LastName = "King", EmployeeID = 1010, Title = "Accountant" });
//Purchasing
childCollection3.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager" });
childCollection3.Add(new Employee() { FirstName = "Michael", LastName = "Blythe", EmployeeID = 1019, Title = "Store Keeper" });
childCollection3.Add(new Employee() { FirstName = "DavId", LastName = "Campbell", EmployeeID = 1020, Title = "Store Keeper" });
//Sales
employeeList.Add(new Employee() { FirstName = "Laura", LastName = "Callahan", EmployeeID = 1005, Title = "Sales Manager", Children = childCollection1 });
employeeList.Add(new Employee() { FirstName = "Anne", LastName = "Dodsworth", EmployeeID = 1011, Title = "Sales Representative", Children = childCollection2 });
//Purchasing
employeeList.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager", Children= childCollection3 });
return employeeList;
}
}
Button command binding to view model
You can load a button for the columns in treegrid using TreeGridTemplateColumn. When loading the buttons, you can bind a command included in view model by using ElementName
binding.
In the following example, the command receives the underlying data object as command parameter, since the DataContext
is binding as command parameter.
<treeGrid:SfTreeGrid x:Name="sfTreeGrid"
ColumnWidthMode="Star"
AllowEditing="True"
AllowFiltering="True"
ChildPropertyName="Children"
AutoGenerateColumns="False"
ItemsSource="{Binding Employees}">
<treeGrid:SfTreeGrid.Columns>
<treeGrid:TreeGridTextColumn HeaderText="First Name" MappingName="FirstName" />
<treeGrid:TreeGridTextColumn HeaderText="Last Name" MappingName="LastName" />
<treeGrid:TreeGridNumericColumn HeaderText="Employee ID" MappingName="EmployeeID" />
<treeGrid:TreeGridTextColumn HeaderText="Title" MappingName="Title" />
<treeGrid:TreeGridTemplateColumn HeaderText="City" MappingName="City" >
<treeGrid:TreeGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Click" Width="160" Height="30" Command="{Binding Path=DataContext.RowDataCommand,ElementName=sfTreeGrid}" CommandParameter="{Binding}"/>
</DataTemplate>
</treeGrid:TreeGridTemplateColumn.CellTemplate>
</treeGrid:TreeGridTemplateColumn>
</treeGrid:SfTreeGrid.Columns>
</treeGrid:SfTreeGrid>
using Syncfusion.UI.Xaml.Core;
public class ViewModel
{
public ViewModel()
{
this.Employees = this.GetEmployees();
rowDataCommand = new DelegateCommand(ChangeCanExecute);
}
private DelegateCommand rowDataCommand;
/// <summary>
/// Gets and sets the rowdata command.
/// </summary>
public DelegateCommand RowDataCommand
{
get
{
return rowDataCommand;
}
set
{
rowDataCommand = value;
}
}
private ObservableCollection<Employee> _employees;
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set { _employees = value; RaisePropertyChanged("Employees"); }
}
/// <summary>
/// Shown the selected record.
/// </summary>
public async void ChangeCanExecute(object obj)
{
var rowDataContent = (obj as Employee);
MessageDialog showDialog = new MessageDialog("SelectedRow Details:\n" +
"FirstName - " + rowDataContent.FirstName +
"\nLastName - " + rowDataContent.LastName +
"\nEmployeeID - " + rowDataContent.EmployeeID +
"\nTitle - " + rowDataContent.Title);
await showDialog.ShowAsync();
}
public static ObservableCollection<Employee> GetEmployees()
{
ObservableCollection<Employee> childCollection1 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection2 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection3 = new ObservableCollection<Employee>();
ObservableCollection<Employee> employeeList = new ObservableCollection<Employee>();
//Management
childCollection1.Add(new Employee() { FirstName = "Andrew", LastName = "Fuller", EmployeeID = 1001, Title = "Vice President" });
childCollection1.Add(new Employee() { FirstName = "Janet", LastName = "Leverling", EmployeeID = 1002, Title = "GM" });
childCollection1.Add(new Employee() { FirstName = "Steven", LastName = "Buchanan", EmployeeID = 1003, Title = "Manager" });
//Accounts
childCollection2.Add(new Employee() { FirstName = "Nancy", LastName = "Davolio", EmployeeID = 1004, Title = "Accounts Manager" });
childCollection2.Add(new Employee() { FirstName = "Margaret", LastName = "Peacock", EmployeeID = 1008, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Michael", LastName = "Suyama", EmployeeID = 1009, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Robert", LastName = "King", EmployeeID = 1010, Title = "Accountant" });
//Purchasing
childCollection3.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager" });
childCollection3.Add(new Employee() { FirstName = "Michael", LastName = "Blythe", EmployeeID = 1019, Title = "Store Keeper" });
childCollection3.Add(new Employee() { FirstName = "DavId", LastName = "Campbell", EmployeeID = 1020, Title = "Store Keeper" });
//Sales
employeeList.Add(new Employee() { FirstName = "Laura", LastName = "Callahan", EmployeeID = 1005, Title = "Sales Manager", Children = childCollection1 });
employeeList.Add(new Employee() { FirstName = "Anne", LastName = "Dodsworth", EmployeeID = 1011, Title = "Sales Representative", Children = childCollection2 });
//Purchasing
employeeList.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager", Children= childCollection3 });
return employeeList;
}
}
Binding ComboBoxColumn ItemsSource from view model
You can bind the ItemsSource
from ViewModel
to TreeGridComboBoxColumn by using the ElementName
binding.
<treeGrid:SfTreeGrid x:Name="sfTreeGrid"
ColumnWidthMode="Star"
AllowEditing="True"
ChildPropertyName="Children"
AutoGenerateColumns="False"
ItemsSource="{Binding Employees}">
<treeGrid:SfTreeGrid.Columns>
<treeGrid:TreeGridTextColumn HeaderText="First Name" MappingName="FirstName" />
<treeGrid:TreeGridTextColumn HeaderText="Last Name" MappingName="LastName" />
<treeGrid:TreeGridNumericColumn HeaderText="Employee ID" MappingName="EmployeeID" />
<treeGrid:TreeGridComboBoxColumn MappingName="Title" ItemsSource="{Binding Path=DataContext.TitleList, ElementName=sfTreeGrid}"/>
</treeGrid:SfTreeGrid.Columns>
</treeGrid:SfTreeGrid>
public class ViewModel : NotificationObject
{
public ViewModel()
{
this.Employees = this.GetEmployees();
titleList = new ObservableCollection<string>();
titleList.Add("Store Keeper");
titleList.Add("Purchase Manager");
titleList.Add("Accountant");
titleList.Add("Accounts Manager");
titleList.Add("Manager");
titleList.Add("GM");
titleList.Add("Vice President");
}
private ObservableCollection<string> titleList;
public ObservableCollection<string> TitleList
{
get
{
return titleList;
}
set
{
titleList = value;
RaisePropertyChanged("TitleList");
}
}
private ObservableCollection<Employee> _employees;
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set { _employees = value; RaisePropertyChanged("Employees"); }
}
public static ObservableCollection<Employee> GetEmployees()
{
ObservableCollection<Employee> childCollection1 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection2 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection3 = new ObservableCollection<Employee>();
ObservableCollection<Employee> employeeList = new ObservableCollection<Employee>();
//Management
childCollection1.Add(new Employee() { FirstName = "Andrew", LastName = "Fuller", EmployeeID = 1001, Title = "Vice President" });
childCollection1.Add(new Employee() { FirstName = "Janet", LastName = "Leverling", EmployeeID = 1002, Title = "GM" });
childCollection1.Add(new Employee() { FirstName = "Steven", LastName = "Buchanan", EmployeeID = 1003, Title = "Manager" });
//Accounts
childCollection2.Add(new Employee() { FirstName = "Nancy", LastName = "Davolio", EmployeeID = 1004, Title = "Accounts Manager" });
childCollection2.Add(new Employee() { FirstName = "Margaret", LastName = "Peacock", EmployeeID = 1008, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Michael", LastName = "Suyama", EmployeeID = 1009, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Robert", LastName = "King", EmployeeID = 1010, Title = "Accountant" });
//Purchasing
childCollection3.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager" });
childCollection3.Add(new Employee() { FirstName = "Michael", LastName = "Blythe", EmployeeID = 1019, Title = "Store Keeper" });
childCollection3.Add(new Employee() { FirstName = "DavId", LastName = "Campbell", EmployeeID = 1020, Title = "Store Keeper" });
//Sales
employeeList.Add(new Employee() { FirstName = "Laura", LastName = "Callahan", EmployeeID = 1005, Title = "Sales Manager", Children = childCollection1 });
employeeList.Add(new Employee() { FirstName = "Anne", LastName = "Dodsworth", EmployeeID = 1011, Title = "Sales Representative", Children = childCollection2 });
//Purchasing
employeeList.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager", Children= childCollection3 });
return employeeList;
}
}
Binding ItemsSource from view model to ComboBox inside data template
You can load a ComboBox inside TreeGridTemplateColumn and bind the ItemsSource
from ViewModel
to ComboBox using ElementName
binding.
<treeGrid:SfTreeGrid x:Name="sfTreeGrid"
ColumnWidthMode="Star"
AllowFiltering="True"
AllowEditing="True"
ChildPropertyName="Children"
AutoGenerateColumns="False"
ItemsSource="{Binding Employees}">
<treeGrid:SfTreeGrid.Columns>
<treeGrid:TreeGridTextColumn HeaderText="First Name" MappingName="FirstName" />
<treeGrid:TreeGridTextColumn HeaderText="Last Name" MappingName="LastName" />
<treeGrid:TreeGridNumericColumn HeaderText="Employee ID" MappingName="EmployeeID" />
<treeGrid:TreeGridTemplateColumn MappingName="Title">
<treeGrid:TreeGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" VerticalAlignment="Center" />
</DataTemplate>
</treeGrid:TreeGridTemplateColumn.CellTemplate>
<treeGrid:TreeGridTemplateColumn.EditTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.TitleList, ElementName=sfTreeGrid}" DisplayMemberPath="{Binding TitleList}" Width="160"/>
</DataTemplate>
</treeGrid:TreeGridTemplateColumn.EditTemplate>
</treeGrid:TreeGridTemplateColumn>
</treeGrid:SfTreeGrid.Columns>
</treeGrid:SfTreeGrid>
public class ViewModel : NotificationObject
{
public ViewModel()
{
this.Employees = this.GetEmployees();
titleList = new ObservableCollection<string>();
titleList.Add("Store Keeper");
titleList.Add("Purchase Manager");
titleList.Add("Accountant");
titleList.Add("Accounts Manager");
titleList.Add("Manager");
titleList.Add("GM");
titleList.Add("Vice President");
}
private ObservableCollection<string> titleList;
public ObservableCollection<string> TitleList
{
get
{
return titleList;
}
set
{
titleList = value;
RaisePropertyChanged("TitleList");
}
}
private ObservableCollection<Employee> _employees;
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set { _employees = value; RaisePropertyChanged("Employees"); }
}
public static ObservableCollection<Employee> GetEmployees()
{
ObservableCollection<Employee> childCollection1 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection2 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection3 = new ObservableCollection<Employee>();
ObservableCollection<Employee> employeeList = new ObservableCollection<Employee>();
//Management
childCollection1.Add(new Employee() { FirstName = "Andrew", LastName = "Fuller", EmployeeID = 1001, Title = "Vice President" });
childCollection1.Add(new Employee() { FirstName = "Janet", LastName = "Leverling", EmployeeID = 1002, Title = "GM" });
childCollection1.Add(new Employee() { FirstName = "Steven", LastName = "Buchanan", EmployeeID = 1003, Title = "Manager" });
//Accounts
childCollection2.Add(new Employee() { FirstName = "Nancy", LastName = "Davolio", EmployeeID = 1004, Title = "Accounts Manager" });
childCollection2.Add(new Employee() { FirstName = "Margaret", LastName = "Peacock", EmployeeID = 1008, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Michael", LastName = "Suyama", EmployeeID = 1009, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Robert", LastName = "King", EmployeeID = 1010, Title = "Accountant" });
//Purchasing
childCollection3.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager" });
childCollection3.Add(new Employee() { FirstName = "Michael", LastName = "Blythe", EmployeeID = 1019, Title = "Store Keeper" });
childCollection3.Add(new Employee() { FirstName = "DavId", LastName = "Campbell", EmployeeID = 1020, Title = "Store Keeper" });
//Sales
employeeList.Add(new Employee() { FirstName = "Laura", LastName = "Callahan", EmployeeID = 1005, Title = "Sales Manager", Children = childCollection1 });
employeeList.Add(new Employee() { FirstName = "Anne", LastName = "Dodsworth", EmployeeID = 1011, Title = "Sales Representative", Children = childCollection2 });
//Purchasing
employeeList.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager", Children= childCollection3 });
return employeeList;
}
}
Binding TreeGrid columns from view model
You can bind the SfTreeGrid.Columns property in ViewModel
by having the binding property of Syncfusion.UI.Xaml.TreeGrid.TreeGridColumns
type. Thus, you can set binding to the SfTreeGrid.Columns
property that provides DataContext
of treegrid in ViewModel
.
<treeGrid:SfTreeGrid x:Name="sfTreeGrid"
ColumnWidthMode="Star"
AllowFiltering="True"
AllowEditing="True"
ChildPropertyName="Children"
Columns="{Binding SfTreeGridColumns, Mode=TwoWay}"
AutoGenerateColumns="False"
ItemsSource="{Binding Employees}">
</treeGrid:SfTreeGrid>
Refer to the following code example in which the treegrid column is populated with some TreeGridTextColumn when creating the ViewModel
instance.
public class ViewModel
{
private TreeGridColumns sfTreeGridColumns;
public ViewModel()
{
SetSfTreeGridColumns();
this.Employees = this.GetEmployees();
}
public TreeGridColumns SfTreeGridColumns
{
get { return sfTreeGridColumns; }
set { this.sfTreeGridColumns = value; }
}
private ObservableCollection<Employee> _employees;
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set { _employees = value; RaisePropertyChanged("Employees"); }
}
/// <summary>
/// To generate the columns for SfTreeGrid.
/// </summary>
protected void SetSfTreeGridColumns()
{
this.sfTreeGridColumns = new TreeGridColumns();
sfTreeGridColumns.Add(new TreeGridTextColumn() { MappingName = "FirstName", HeaderText = "First Name" });
sfTreeGridColumns.Add(new TreeGridTextColumn() { MappingName = "LastName", HeaderText = "Last Name" });
sfTreeGridColumns.Add(new TreeGridTextColumn() { MappingName = "EmployeeID", HeaderText = "Employee ID", TextAlignment = TextAlignment.Right });
sfTreeGridColumns.Add(new TreeGridTextColumn() { MappingName = "Title", HeaderText = "Title" });
}
public static ObservableCollection<Employee> GetEmployees()
{
ObservableCollection<Employee> childCollection1 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection2 = new ObservableCollection<Employee>();
ObservableCollection<Employee> childCollection3 = new ObservableCollection<Employee>();
ObservableCollection<Employee> employeeList = new ObservableCollection<Employee>();
//Management
childCollection1.Add(new Employee() { FirstName = "Andrew", LastName = "Fuller", EmployeeID = 1001, Title = "Vice President" });
childCollection1.Add(new Employee() { FirstName = "Janet", LastName = "Leverling", EmployeeID = 1002, Title = "GM" });
childCollection1.Add(new Employee() { FirstName = "Steven", LastName = "Buchanan", EmployeeID = 1003, Title = "Manager" });
//Accounts
childCollection2.Add(new Employee() { FirstName = "Nancy", LastName = "Davolio", EmployeeID = 1004, Title = "Accounts Manager" });
childCollection2.Add(new Employee() { FirstName = "Margaret", LastName = "Peacock", EmployeeID = 1008, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Michael", LastName = "Suyama", EmployeeID = 1009, Title = "Accountant" });
childCollection2.Add(new Employee() { FirstName = "Robert", LastName = "King", EmployeeID = 1010, Title = "Accountant" });
//Purchasing
childCollection3.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager" });
childCollection3.Add(new Employee() { FirstName = "Michael", LastName = "Blythe", EmployeeID = 1019, Title = "Store Keeper" });
childCollection3.Add(new Employee() { FirstName = "DavId", LastName = "Campbell", EmployeeID = 1020, Title = "Store Keeper" });
//Sales
employeeList.Add(new Employee() { FirstName = "Laura", LastName = "Callahan", EmployeeID = 1005, Title = "Sales Manager", Children = childCollection1 });
employeeList.Add(new Employee() { FirstName = "Anne", LastName = "Dodsworth", EmployeeID = 1011, Title = "Sales Representative", Children = childCollection2 });
//Purchasing
employeeList.Add(new Employee() { FirstName = "Pamela", LastName = "Ansman-Wolfe", EmployeeID = 1018, Title = "Purchase Manager", Children= childCollection3 });
return employeeList;
}
}