Checkbox in WinUI TreeView
22 Dec 202124 minutes to read
The TreeView provides support for loading CheckBox
in each node, and allows users to check/uncheck the corresponding node. So, you should add checkbox in the ItemTemplate of the TreeView
and bind the IsChecked property of the TreeViewNode.
Working with CheckBox in Bound Mode
When you are populating treeview nodes from ItemsSource, then you can get or set the checked items by using CheckedItems property.
The TreeView
supports to check multiple items through binding the CheckedItems property from view model with ObservableCollection<object>
type.
NOTE
Set ItemTemplateDataContextType as
Node
to bind theTreeViewNode.IsChecked
property toCheckBox
inItemTemplate
.
NOTE
TreeView process and sets TreeViewNode.IsChecked based on
CheckedItems
only when you are bindingItemsSource
.
<Page x:Class="syncfusion.treeviewdemos.winui.CheckBoxPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:syncfusion.treeviewdemos.winui"
xmlns:treeView="using:Syncfusion.UI.Xaml.TreeView"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
NavigationCacheMode="Disabled">
<Page.DataContext>
<local:CheckBoxView />
</Page.DataContext>
<Grid>
<treeView:SfTreeView x:Name="treeView"
AutoExpandMode="AllNodes"
BorderBrush="LightGray"
BorderThickness="1"
CheckBoxMode="Recursive"
CheckedItems="{Binding CheckedItems}"
ChildPropertyName="Models"
ExpandActionTrigger="Expander"
IsAnimationEnabled="True"
ItemTemplateDataContextType="Node"
ItemsSource="{Binding Items}"
NodePopulationMode="Instant">
<treeView:SfTreeView.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox x:Name="checkBox"
Content="{Binding Content.State}"
local:NullableTreeCheckbox.IsEnabled="true"
local:NullableTreeCheckbox.IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</treeView:SfTreeView.ItemTemplate>
</treeView:SfTreeView>
</Grid>
</Page>
public class CheckBoxView : NotificationObject
{
public ObservableCollection<object> CheckedItems { get; set; }
public ObservableCollection<CheckBoxModel> Items { get; set; }
public CheckBoxView()
{
Items = new ObservableCollection<CheckBoxModel>();
var country1 = new CheckBoxModel { State = "Australia" };
var country2 = new CheckBoxModel { State = "Brazil" };
var country3 = new CheckBoxModel { State = "China" };
var country4 = new CheckBoxModel { State = "France" };
var country5 = new CheckBoxModel { State = "India" };
var country6 = new CheckBoxModel { State = "USA" };
var country7 = new CheckBoxModel { State = "UK" };
var country8 = new CheckBoxModel { State = "Russia" };
var country9 = new CheckBoxModel { State = "Canada" };
var country10 = new CheckBoxModel { State = "Germany" };
var aus_state1 = new CheckBoxModel { State = "New South Wales" };
var aus_state2 = new CheckBoxModel { State = "Victoria" };
var aus_state3 = new CheckBoxModel { State = "South Australia" };
var aus_state4 = new CheckBoxModel { State = "Western Australia" };
var brazil_state1 = new CheckBoxModel { State = "Parana" };
var brazil_state2 = new CheckBoxModel { State = "Ceara" };
var brazil_state3 = new CheckBoxModel { State = "Acre" };
var china_state1 = new CheckBoxModel { State = "Guangzhou" };
var china_state2 = new CheckBoxModel { State = "Shanghai" };
var china_state3 = new CheckBoxModel { State = "Beijing" };
var china_state4 = new CheckBoxModel { State = "Shantou" };
var france_state1 = new CheckBoxModel { State = "Pays de la Loire" };
var france_state2 = new CheckBoxModel { State = "Aquitaine" };
var france_state3 = new CheckBoxModel { State = "Brittany" };
var france_state4 = new CheckBoxModel { State = "Lorraine" };
var ind_State1 = new CheckBoxModel { State = "Assam" };
var ind_State2 = new CheckBoxModel { State = "Bihar" };
var ind_State3 = new CheckBoxModel { State = "Tamil Nadu" };
var ind_State4 = new CheckBoxModel { State = "Punjab" };
var usa_state1 = new CheckBoxModel { State = "New York" };
var usa_state2 = new CheckBoxModel { State = "California" };
var usa_state3 = new CheckBoxModel { State = "Texas" };
var usa_state4 = new CheckBoxModel { State = "Washington" };
var usa_state5 = new CheckBoxModel { State = "Florida" };
var uk_state1 = new CheckBoxModel { State = "England" };
var uk_state2 = new CheckBoxModel { State = "Wales" };
var uk_state3 = new CheckBoxModel { State = "Scotland" };
var uk_state4 = new CheckBoxModel { State = "Northern Ireland" };
var russia_state1 = new CheckBoxModel { State = "Mordovia" };
var russia_state2 = new CheckBoxModel { State = "Chechnya" };
var russia_state3 = new CheckBoxModel { State = "Tatarstan" };
var russia_state4 = new CheckBoxModel { State = "Dagestan" };
var canada_state1 = new CheckBoxModel { State = "Alberta" };
var canada_state2 = new CheckBoxModel { State = "Manitoba" };
var canada_state3 = new CheckBoxModel { State = "New Brunswick" };
var canada_state4 = new CheckBoxModel { State = "Quebec" };
var germany_state1 = new CheckBoxModel { State = "Berlin" };
var germany_state2 = new CheckBoxModel { State = "Hamburg" };
var germany_state3 = new CheckBoxModel { State = "Bremen" };
var germany_state4 = new CheckBoxModel { State = "Lower Saxony" };
country1.Models.Add(aus_state1);
country1.Models.Add(aus_state2);
country1.Models.Add(aus_state3);
country1.Models.Add(aus_state4);
country2.Models.Add(brazil_state1);
country2.Models.Add(brazil_state2);
country2.Models.Add(brazil_state3);
country3.Models.Add(china_state1);
country3.Models.Add(china_state2);
country3.Models.Add(china_state3);
country3.Models.Add(china_state4);
country4.Models.Add(france_state1);
country4.Models.Add(france_state2);
country4.Models.Add(france_state3);
country4.Models.Add(france_state4);
country5.Models.Add(ind_State1);
country5.Models.Add(ind_State2);
country5.Models.Add(ind_State3);
country5.Models.Add(ind_State4);
country6.Models.Add(usa_state1);
country6.Models.Add(usa_state2);
country6.Models.Add(usa_state3);
country6.Models.Add(usa_state4);
country6.Models.Add(usa_state5);
country7.Models.Add(uk_state1);
country7.Models.Add(uk_state2);
country7.Models.Add(uk_state3);
country7.Models.Add(uk_state4);
country8.Models.Add(russia_state1);
country8.Models.Add(russia_state2);
country8.Models.Add(russia_state3);
country8.Models.Add(russia_state4);
country9.Models.Add(canada_state1);
country9.Models.Add(canada_state2);
country9.Models.Add(canada_state3);
country9.Models.Add(canada_state4);
country10.Models.Add(germany_state1);
country10.Models.Add(germany_state2);
country10.Models.Add(germany_state3);
country10.Models.Add(germany_state4);
Items.Add(country1);
Items.Add(country2);
Items.Add(country3);
Items.Add(country4);
Items.Add(country5);
Items.Add(country6);
Items.Add(country7);
Items.Add(country8);
Items.Add(country9);
Items.Add(country10);
CheckedItems = new ObservableCollection<object>();
CheckedItems.Add(aus_state3);
CheckedItems.Add(aus_state4);
CheckedItems.Add(brazil_state2);
CheckedItems.Add(brazil_state3);
CheckedItems.Add(china_state3);
}
}
public class NullableTreeCheckbox : DependencyObject
{
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(NullableTreeCheckbox), new PropertyMetadata(false, OnIsEnabledChanged));
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked", typeof(object),
typeof(NullableTreeCheckbox), new PropertyMetadata(default(object), IsCheckedChanged));
private static readonly DependencyProperty IsInternalCheckedProperty =
DependencyProperty.RegisterAttached("IsInternalChecked", typeof(object),
typeof(NullableTreeCheckbox), new PropertyMetadata(null, OnIsInternalCheckedChanged));
public static bool GetIsEnabled(DependencyObject obj)
{
if (obj == null)
return false;
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
if (obj == null)
return;
obj.SetValue(IsEnabledProperty, value);
}
public static object GetIsChecked(DependencyObject obj)
{
if (obj == null)
return false;
return (bool?)obj.GetValue(IsCheckedProperty);
}
public static void SetIsChecked(DependencyObject obj, object value)
{
if (obj == null)
return;
obj.SetValue(IsCheckedProperty, value);
}
private static void OnIsInternalCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SetIsChecked(d, (bool?)e.NewValue);
}
private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as Microsoft.UI.Xaml.Controls.CheckBox;
if ((bool)e.NewValue)
{
var binding = new Binding
{
Path = new PropertyPath("IsChecked"),
Mode = BindingMode.TwoWay,
Source = checkbox,
};
checkbox.SetBinding(NullableTreeCheckbox.IsInternalCheckedProperty, binding);
}
}
private static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as Microsoft.UI.Xaml.Controls.CheckBox;
bool? newValue = null;
if (e.NewValue is bool?)
newValue = (bool?)e.NewValue;
else if (e.NewValue != null)
newValue = (bool)e.NewValue;
if (!checkbox.IsChecked.Equals(newValue))
checkbox.IsChecked = newValue;
}
}
public class CheckBoxModel : NotificationObject
{
private ObservableCollection<CheckBoxModel> models;
private string state;
public CheckBoxModel()
{
Models = new ObservableCollection<CheckBoxModel>();
}
public ObservableCollection<CheckBoxModel> Models
{
get
{
return models;
}
set
{
models = value;
this.RaisePropertyChanged(nameof(Models));
}
}
public string State
{
get
{
return state;
}
set
{
state = value;
this.RaisePropertyChanged(nameof(State));
}
}
}
NOTE
Working with CheckBox in Unbound Mode
You can directly set the checkbox state by setting the TreeViewNode.IsChecked property value while creating nodes.
<Page x:Class="syncfusion.treeviewdemos.winui.CheckBoxPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:syncfusion.treeviewdemos.winui"
xmlns:treeView="using:Syncfusion.UI.Xaml.TreeView"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
NavigationCacheMode="Disabled">
<Grid>
<syncfusion:SfTreeView x:Name="TreeView"
Width="400"
BorderThickness="1"
BorderBrush="LightGray"
IsAnimationEnabled="True"
ItemTemplateDataContextType="Node"
CheckBoxMode="Recursive">
<treeView:SfTreeView.Nodes>
<treeView:TreeViewNode Content="Grains"
IsExpanded="True"
IsChecked="True">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Cereals"
IsExpanded="True">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Rice"
IsChecked="True" />
<treeView:TreeViewNode Content="Barley" />
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
<treeView:TreeViewNode Content="Oilseeds">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Safflower"
IsChecked="True" />
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
<treeView:TreeViewNode Content="Fruits"
IsExpanded="true">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Orange"
IsChecked="True" />
<treeView:TreeViewNode Content="Apples"
IsExpanded="true" />
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
<treeView:TreeViewNode Content="Vegetables"
IsExpanded="true"
IsChecked="True">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Root Vegetables"
IsExpanded="true">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Potato"
IsChecked="True" />
<treeView:TreeViewNode Content="Carrot" />
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
<treeView:TreeViewNode Content="Podded">
<treeView:TreeViewNode.ChildNodes>
<treeView:TreeViewNode Content="Peanut"
IsChecked="True" />
<treeView:TreeViewNode Content="Lentil" />
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
</treeView:TreeViewNode.ChildNodes>
</treeView:TreeViewNode>
</treeView:SfTreeView.Nodes>
<treeView:SfTreeView.ItemTemplate>
<DataTemplate>
<Grid>
<CheckBox x:Name="checkBox"
Content="{Binding Content}"
local:NullableTreeCheckbox.IsEnabled="true"
local:NullableTreeCheckbox.IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</treeView:SfTreeView.ItemTemplate>
</treeView:SfTreeView>
</Grid>
</Page>
public class NullableTreeCheckbox : DependencyObject
{
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(NullableTreeCheckbox), new PropertyMetadata(false, OnIsEnabledChanged));
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked", typeof(object),
typeof(NullableTreeCheckbox), new PropertyMetadata(default(object), IsCheckedChanged));
private static readonly DependencyProperty IsInternalCheckedProperty =
DependencyProperty.RegisterAttached("IsInternalChecked", typeof(object),
typeof(NullableTreeCheckbox), new PropertyMetadata(null, OnIsInternalCheckedChanged));
public static bool GetIsEnabled(DependencyObject obj)
{
if (obj == null)
return false;
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
if (obj == null)
return;
obj.SetValue(IsEnabledProperty, value);
}
public static object GetIsChecked(DependencyObject obj)
{
if (obj == null)
return false;
return (bool?)obj.GetValue(IsCheckedProperty);
}
public static void SetIsChecked(DependencyObject obj, object value)
{
if (obj == null)
return;
obj.SetValue(IsCheckedProperty, value);
}
private static void OnIsInternalCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SetIsChecked(d, (bool?)e.NewValue);
}
private static void OnIsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as Microsoft.UI.Xaml.Controls.CheckBox;
if ((bool)e.NewValue)
{
var binding = new Binding
{
Path = new PropertyPath("IsChecked"),
Mode = BindingMode.TwoWay,
Source = checkbox,
};
checkbox.SetBinding(NullableTreeCheckbox.IsInternalCheckedProperty, binding);
}
}
private static void IsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var checkbox = d as Microsoft.UI.Xaml.Controls.CheckBox;
bool? newValue = null;
if (e.NewValue is bool?)
newValue = (bool?)e.NewValue;
else if (e.NewValue != null)
newValue = (bool)e.NewValue;
if (!checkbox.IsChecked.Equals(newValue))
checkbox.IsChecked = newValue;
}
}
NOTE
CheckBox State
The TreeView
process IsChecked property (checkbox state) of TreeViewNode
based on CheckBoxMode property. The CheckBoxMode
defines how parent and child node’s checkbox state updates when user check or un-check the node. By default, its value is None
.
The Checkbox contains the following three states:
-
None
: Check and uncheck will be updated only in the view, but it will not affect theCheckedItems
collection. -
Individual
: This Checkbox state affect individual node only, and it does not affect the parent node or child nodes checkbox state orIsChecked
property value. -
Recursive
: Check and uncheck the node value affects the parent and child nodes checkbox state. For example, if parent nodes checkbox state is check/uncheck then all of its child nodes checkbox state will be updated. If all the child nodes in check/uncheck state within the parent node, then parent node checkbox state will be updated. If any of the child node is checked and some child nodes not checked, then the parent node will be in intermediate state.
<treeView:SfTreeView x:Name="treeView" CheckBoxMode="Recursive" />
treeView.CheckBoxMode = CheckBoxMode.Recursive;
NOTE
In recursive mode, the parent nodes checkbox state or
IsChecked
property value is updated only in UI interaction.
Get or Set Checked Items
Get or Set Checked Items in Bound Mode
You can get or set list of items to be checked or un-checked by using CheckedItems property.
When the CheckBoxMode is other than None
, the individual TreeViewNode
or collection of TreeViewNode
can be checked from the code by setting the CheckedItems
, or adding items to the CheckedItems
property based on the CheckBoxMode
.
NOTE
Programmatically adding or removing the node value not affects their parent and child nodes checkbox state.
treeView.CheckedItems.Add(viewModel.Items[2]);
treeView.CheckedItems.Add(viewModel.Items[3]);
Events
NodeChecked event
The NodeChecked event raised when checking and unchecking the checkbox at run time. The NodeCheckedEventArgs has the following members, which provide information for the NodeChecked
event.
-
Node
: Gets theTreeViewNode
and data associated with the checked item as its arguments.
treeView.NodeChecked += treeView_NodeChecked;
private void treeView_NodeChecked(object sender, NodeCheckedEventArgs e)
{
}
NOTE
NodeChecked
event occurs only in UI interactions.