Hi; you calculate SelectedCount in ViewModel like in following demo:
<Window x:Class="WpfApp1.Window35"
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="clr-namespace:WpfApp35"
mc:Ignorable="d"
Title="Window35" Height="450" Width="800">
<Window.Resources>
<local:ViewModel x:Key="vm"/>
<Style x:Key="HighlightingTextStyle" TargetType="Label">
<Setter Property="FontStyle" Value="Italic"/>
</Style>
</Window.Resources>
<Grid DataContext="{StaticResource vm}">
<StatusBar VerticalAlignment="Top">
<Label Content="Selected Devices:" Margin="1,1,0,1"/>
<Label Content="{Binding SelectedDevicesCount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StatusBar>
<TreeView ItemsSource="{Binding TreeViewDataCollection}" Margin="0 40 0 0">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding HostGroupName}" DataType="{x:Type local:RootNameList}">
<StackPanel Orientation="Horizontal">
<Label Style="{StaticResource HighlightingTextStyle}" Content="{Binding RootSubnet}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Host}" DataType="{x:Type local:HostGroup}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsParentChecked}" IsThreeState="True"/>
<Label Style="{StaticResource HighlightingTextStyle}" Content="{Binding GroupName}" Tag="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:HostName}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChildChecked}"/>
<Label Style="{StaticResource HighlightingTextStyle}" Content="{Binding Host}" Tag="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
Classes:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;
namespace WpfApp35
{
public class ViewModel : BaseClass
{
public ViewModel()
{
LoadData();
SetHandler();
cvs.Source = col;
}
private void SetHandler()
{
foreach (var rnl in col)
foreach (var hg in rnl.HostGroupName)
{
hg.SetHandler();
hg.PropertyChanged += Hg_PropertyChanged;
}
}
private void Hg_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
SelectedDevicesCount = 0;
foreach (var rnl in col)
foreach (var hg in rnl.HostGroupName) SelectedDevicesCount += hg.SelectedCount;
OnPropertyChanged(nameof(SelectedDevicesCount));
}
private void LoadData()
{
for (int i = 1; i < 10; i++)
{
var rnl = new RootNameList { RootSubnet = $"RootSubnet{i}" };
for (int k = 0; k < 10; k++)
{
var hg = new HostGroup { GroupName = $"GroupName {k + i * 10}" };
rnl.HostGroupName.Add(hg);
for (int l = 0; l < 10; l++)
{
var h = new HostName() { Host = $"Host {l}" };
hg.Host.Add(h);
}
}
col.Add(rnl);
}
}
public int SelectedDevicesCount { get; set; }
private CollectionViewSource cvs = new CollectionViewSource();
private ObservableCollection<RootNameList> col = new ObservableCollection<RootNameList>();
public ICollectionView TreeViewDataCollection { get => cvs.View; }
}
public class RootNameList
{
public string RootSubnet { get; set; }
public List<HostGroup> HostGroupName { get; set; } = new List<HostGroup>();
}
public class HostGroup : BaseClass
{
private bool? _IsParentChecked = false;
public bool? IsParentChecked
{
get => this._IsParentChecked;
set
{
if (!value.HasValue) value = false;
this._IsParentChecked = value;
foreach (var h in Host) h.IsChildChecked = value.Value;
OnPropertyChanged();
}
}
public string GroupName { get; set; }
public List<HostName> Host { get; set; } = new List<HostName>();
public void SetHandler()
{
foreach (var hn in Host) hn.PropertyChanged += h_PropertyChanged;
}
public int SelectedCount { get; set; } = 0;
internal void h_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
int iFalse = 0;
SelectedCount = 0;
foreach (var h in Host) if (h.IsChildChecked) SelectedCount++; else iFalse++;
if (SelectedCount > 0 && iFalse == 0) this._IsParentChecked = true;
if (SelectedCount == 0 && iFalse > 0) this._IsParentChecked = false;
if (SelectedCount > 0 && iFalse > 0) this._IsParentChecked = null;
OnPropertyChanged(nameof(IsParentChecked));
}
}
public class HostName : BaseClass
{
private bool _isChildChecked = false;
public bool IsChildChecked
{
get => this._isChildChecked;
set
{
this._isChildChecked = value;
OnPropertyChanged();
}
}
public string Host { get; set; }
public string HostType { get; set; }
}
public class BaseClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged([CallerMemberName] string nameProp = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameProp));
}
}