繁体   English   中英

多级 Select WPF TreeView

[英]Multi Select with Multiple Level in WPF TreeView

我正在尝试使用多级 WPF 树视图实现多选。 为此,我禁用了 WPF 选择,而是突出显示所选项目并对其进行处理。

此实现适用于 Ctrl 按钮和 select 随机。

但是对于 shift select,如果我尝试突出显示未展开的树节点,我可以突出显示树节点而不是其子节点。 要求是扩展树节点并突出显示子节点。

展开树节点后,我无法从 ItemContainerGenerator 获取子节点的容器。它总是返回 null

无论我尝试到现在

1.展开Parent TreeViewItem后使用UpdateLayout(); ItemContainerGenerator.ContainerFromItem(item)返回 null)

  1. 关闭虚拟化堆栈。

有什么方法可以让 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="&#xE76C;" 
                                   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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM