从 TreeViewItem 的 ItemSource 读取 "IsExpanded" 属性

Reading the "IsExpanded" property from the ItemSource of a TreeViewItem

所以我希望 TreeView 项的 IsExpanded 属性 反映在数据上下文中。

        <TreeView x:Name="TreeViewMonitorEvents" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="1" Grid.RowSpan="5"
              ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Page}, Path=MonitorEventCatagories}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type tree:TreeGroup}" ItemsSource="{Binding Members}" >
                <StackPanel Orientation="Horizontal" VerticalAlignment="Center" MouseMove="DragDrop_MouseMove_TreeGroup">
                    <CheckBox Name="CheckboxTreeGroup" IsChecked="{Binding Path=(tree:TreeItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                          Template="{DynamicResource MonitoringUICheckBox}" Style="{StaticResource MonitoringUICheckBoxStyling}"
                              MouseMove="DragDrop_MouseMove_TreeGroup" Checked="CheckboxTreeGroup_Checked" Unchecked="CheckboxTreeGroup_Unchecked">
                    </CheckBox>
                    <TextBlock Text="{Binding Name}" Style="{StaticResource MonitorUIText}" MouseMove="DragDrop_MouseMove_TreeGroup"/>
                </StackPanel>
                <HierarchicalDataTemplate.ItemContainerStyle>
                    <Style TargetType="{x:Type TreeViewItem}"  >
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded,Mode=TwoWay}" />
                    </Style>
                </HierarchicalDataTemplate.ItemContainerStyle>
            </HierarchicalDataTemplate>

即 TreeGroup Class。在这里查看树组:

namespace RTX64MonitorUtility.TreeView
{
    //Data class.  Holds information in the Datacontext section of the UI Elements it is attached to.
    public class TreeGroup : DependencyObject, IParent<object>
    {


        public string Name { get; set; }
        public List<TreeMonitoringEvent> Members { get; set; }
        public IEnumerable<object> GetChildren()
        {
            return Members;
        }

        public bool IsExpanded { get; set; } = false;
    }
}

这是它从中提取的列表:

namespace RTX64MonitorUtility.Pages
{
    /// <summary>
    /// Interaction logic for EventsAndTriggers.xaml
    /// </summary>
    public partial class EventsAndTriggers : Page
    {
         public ObservableCollection<TreeGroup> MonitorEventCatagories { get; set; }
         ...
    }
}

我的主要目标是,如果 TreeGroup 项未展开,则不会触发孩子的 CheckedUnchecked 事件,因此我需要为他们执行所需的操作。如果我能找到一种从这些事件中读取 IsExpanded 值的方法,那也是一个解决方案。

您通常通过使用以项目容器为目标的 Style 将项目容器的属性(如 TreeViewItem.IsExpandedListBoxItem.IsSelected 等)绑定到您的数据模型。 item容器的DataContext是数据模型:

<TreeView>
  <TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
      <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
    </Style>
  </TreeView.ItemContainerStyle>
</TreeView>

接下来,正确实现数据模型。作为数据绑定源的属性必须作为依赖属性(对于依赖对象)实现或引发 INotifyPropertyChanged.PropertyChanged 事件。

由于 DependencyObject 扩展了 DispatcherObject,任何扩展 DependencyObject 的 class 都是线程仿射的:在 WPF 中,DispatcherObject 只能由与其关联的 Dispatcher 访问与.
出于这个原因,您通常更喜欢 INotifyPropertyChanged 数据模型。
DependencyObject 用于根据定义绑定到 Dispatcher 线程的 UI 个对象。

// Let the model implement the INotifyPropertyChanged interface
public class TreeGroup : INotifyPropertyChanged, IParent<object>
{
  // Follow this pattern for all properties that will change 
  // and are source of a data binding.
  private bool isExpanded;
  public IsExpanded 
  { 
    get => this.isExpanded; 
    set; 
    {
      this.isExpanded = value;
      OnPropertyChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  private void OnPropertyChanged([CallerMemberName] string propertyName = "")
    => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

Microsoft Docs: Data binding overview (WPF .NET)