[英]Multi Select with Multiple Level in WPF TreeView
我正在尝试使用多级 WPF 树视图实现多选。 为此,我禁用了 WPF 选择,而是突出显示所选项目并对其进行处理。
此实现适用于 Ctrl 按钮和 select 随机。
但是对于 shift select,如果我尝试突出显示未展开的树节点,我可以突出显示树节点而不是其子节点。 要求是扩展树节点并突出显示子节点。
展开树节点后,我无法从 ItemContainerGenerator 获取子节点的容器。它总是返回 null
无论我尝试到现在
1.展开Parent TreeViewItem后使用UpdateLayout(); ( ItemContainerGenerator.ContainerFromItem(item)返回 null)
有什么方法可以让 ItemContainerGenerator 在扩展 TreeNode 后立即生成项目
任何帮助表示赞赏!
您不应该对项目容器进行操作,而是对项目进行操作。
为此,您需要将IsSelected
属性添加到 model。 您还需要 select 一个节点的子项。
为了在TreeViewItem
上注册MouseBinding
,您必须覆盖TreeViewItem
的默认ControlTemplate
。 MouseBinding
定义了一个在"CTRL + LeftClick" MouseGesture
触发的 MouseGesture。 使用MouseBinding
注册的ICommand
通过切换IsSelected
属性来执行项目的实际选择。
要获取所选项目,您只需遍历源集合(遍历树结构)以收集IsSelected
等于true
的所有项目。
树项.cs
public class TreeItem : INotifyPropertyChanged
{
public TreeItem(string value)
{
this.Value = value;
this.Children = new ObservableCollection<TreeItem>();
}
private void SelectAllChildren(IEnumerable<TreeItem> children, bool isSelected)
{
foreach (TreeItem child in children)
{
child.IsSelected = isSelected;
SelectAllChildren(child.Children, isSelected);
}
}
public string Value { get; set; }
public ObservableCollection<TreeItem> Children { get; set; }
// Toggle IsSelected
public ICommand SelectItemCommand => new RelayCommand(param => this.IsSelected ^= true);
private bool isSelected;
public bool IsSelected
{
get => this.isSelected;
set
{
this.isSelected = value;
OnPropertyChanged();
SelectAllChildren(this.Children, this.IsSelected);
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion Implementation of INotifyPropertyChanged
}
视图模型.cs
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
this.TreeItems = new ObservableCollection<TreeItem>();
}
private IEnumerable<TreeItem> GetSelectedItems(IEnumerable<TreeItem> items)
{
List<TreeItem> selectedItems = new List<TreeItem>();
foreach (TreeItem item in items)
{
if (item.IsSelected)
{
selectedItems.Add(item);
}
else // Check if unselected node has selected child nodes
{
var selectedChildItems = GetSelectedItems(item.Children);
selectedItems.AddRange(selectedChildItems);
}
}
return selectedItems;
}
public ObservableCollection<TreeItem> TreeItems { get; set; }
}
主窗口.xaml
<Window>
<Window.Resources>
<ViewModel />
</Window.Resources>
<TreeView ItemsSource="{Binding TreeItems}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type TreeItem}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Value}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeViewItem">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<StackPanel>
<StackPanel Orientation="Horizontal">
<ToggleButton x:Name="Expander"
IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
Background="Transparent"
BorderThickness="0"
RenderTransformOrigin="0.5, 0.5">
<ToggleButton.RenderTransform>
<RotateTransform />
</ToggleButton.RenderTransform>
<ToggleButton.Content>
<TextBlock Text=""
FontFamily="Segoe MDL2 Assets" />
</ToggleButton.Content>
</ToggleButton>
<Border x:Name="SelectionBorder">
<ContentPresenter x:Name="PART_Header"
Content="{TemplateBinding Header}">
<!-- Register to handle CTRL+LeftClick gesture -->
<ContentPresenter.InputBindings>
<MouseBinding Command="{Binding SelectItemCommand}">
<MouseBinding.Gesture>
<MouseGesture Modifiers="Control"
MouseAction="LeftClick" />
</MouseBinding.Gesture>
</MouseBinding>
</ContentPresenter.InputBindings>
</ContentPresenter>
</Border>
</StackPanel>
<ItemsPresenter x:Name="ItemsHost"
Visibility="Collapsed"
Margin="12,0,0,0" />
</StackPanel>
<!-- Animate the node's expander -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpansionStates">
<VisualState x:Name="Expanded">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Expander"
Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)"
To="90"
Duration="0:0:0.1" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ItemsHost"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="0:0:0"
Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Collapsed" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="False">
<Setter TargetName="Expander"
Property="Visibility"
Value="Collapsed" />
</Trigger>
<!-- Handle item selection visuals -->
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter TargetName="SelectionBorder"
Property="Background"
Value="DodgerBlue" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</Window>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.