目標效果
初始載入
選中葉子節點
操作中間節點
實現思路
TreeView
資料來源集合的子項ViewModel
部分
BindableBase
為 Prism
中對應的Vm
基類,讀者也可以按自身需求實現屬性通知介面(INotifyPropertyChanged
)的基類。
public class ModuleNode:BindableBase
{
//public bool IsChecked { get; set; } //屬性需要設定為可空型別
//核取方塊狀態
private bool? isChecked;
public bool? IsChecked
{
get { return isChecked; }
set { SetProperty(ref isChecked, value); }
}
// 子節點集合
public List<ModuleNode> Children { get; set; }
// 父節點物件
public ModuleNode Parent { get; set; }
}
主頁面ViewModel
public class MainViewModel:BindableBase
{
public DelegateCommand<ModuleNode> ModuleCkCommand { get; set; }
public MainViewModel()
{
ModuleCkCommand = new DelegateCommand<ModuleNode>(ModuleCkMethod);
}
/// <summary>
/// 模組選中函式
/// </summary>
/// <param name="node">操作選中物件</param>
private void ModuleCkMethod(ModuleNode node)
{
// 子節點level-1總數
int childCount = node.Children.Count;
// 選中節點狀態
Debug.WriteLine($"更新選中項:{node.Name} {node.IsChecked}");
// 選中子節點更新
if (childCount > 0)
{
// 節點狀態
bool? ischeck = node.IsChecked;
foreach (var child in node.Children)
{
child.IsChecked = ischeck;
Debug.WriteLine($"更新子項:{child.Name} {child.IsChecked}");
// 遞迴操作子節點下層
ModuleCkMethod(child);
}
}
// 父級節點更新
ModuleParentCkMethod(node.Parent);
}
/// <summary>
/// 更新父級節點狀態
/// </summary>
/// <param name="parent">父級物件</param>
private void ModuleParentCkMethod(ModuleNode parent)
{
if (parent == null)
{
return;
}
// 子集深度level-1 選中項 非選中項 null狀態
int childCount = parent.Children.Count;
int ckCount = parent.Children.Count(child => child.IsChecked == true);
int uckCount = parent.Children.Count(child => child.IsChecked == false);
int nullCount = parent.Children.Count(child => child.IsChecked == null);
// 子節點是否存在null,若存在則父級節點直接設定為null
if (nullCount != 0)
{
parent.IsChecked = null;
}
else // 判定選中和非選中是否與下級子節點總數一致,一致時,則更新父節點狀態true/false
{
if (ckCount == childCount)
{
parent.IsChecked = true;
}
else if (uckCount == childCount)
{
parent.IsChecked = false;
}
// 判定選中和非選中是否與下級子節點總數一致,不一致時,則更新父節點狀態為null
else
{
parent.IsChecked = null;
}
}
Debug.WriteLine($"更新父級:{parent.Name} {parent.IsChecked}");
// 遞迴更新父級狀態
ModuleParentCkMethod(parent.Parent);
}
}
UI部分
其中需要注意的是CheckBox
對應的啟用三狀態(True、False、null)屬性IsThreeState
,預設為False
,不啟用。
<TreeView x:Name="TreeData" ItemsSource="{Binding TreeItemSources}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Path=IsChecked}" Command="{Binding DataContext.ModuleCkCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=DataContext}">
</CheckBox>
<ContentPresenter VerticalAlignment="Center" Content="{Binding Path=Name}" Margin="5,0"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>