我有一个可观察到的嵌套对象集合,我在WPF中以TreeView显示这些对象.

public class NestedContainer
{
    public FXR1.FXContainer myContainer { get; set; }
    public string XID { get { return myContainer.XID; } }
    public FXR1.FXActionData ActionData { get { return myContainer.ActionData; } }
    public FXR1.FXModifier Modifier { get { return myContainer.Modifier; } }
    public List<NestedContainer> childContainers { get; set; } = new List<NestedContainer>();
}

我成功地创建了我想要的嵌套 struct ,使用了下面的XAML代码,它显示在树视图中,如下所示:

<TreeView x:Name="FXNodeTree" Grid.Row="1" Grid.Column="1" ItemsSource="{Binding}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:NestedContainer}" ItemsSource="{Binding Path=childContainers}">
            <TextBlock Text="{Binding Path=XID}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Current display example

但是,我也try 将与每个容器相关联的ActionDataModifier(如果有的话)显示为TreeView中位于容器childContainers的正下方的项.这些项没有自己的子容器,因此它们只是属于每个容器的附加信息.经过一些研究后,我最初的 idea 是在childContainers的基础上使用多重绑定和绑定ActionDataModifier,但我找不到任何类似的例子,所以我不确定这是否是理想的解决方案.我对WPF的了解非常初级,所以如果这是一个非常基本的问题,或者如果我错过了一个明显的解决方案,我表示歉意.如有任何帮助,我们不胜感激.

推荐答案

如果我理解正确的话,您希望显示每个 node 数据的附加信息.

For this purpose, you should override the default ControlTeplate of the TreeViewItem. This way you can inject a second content host below the items host (ItemsPresenter).
If you introduce an attached property to hold a DataTemplate that describes the additional content you can avoid to subclass TreeViewItem. This attached property can be defined on any suitable type. This example chooses the MainWindow.

为了避免内存泄漏,绑定源必须始终实现INotifyPropertyChanged,或者最好将属性实现为依赖项属性.即使财产价值不会改变.

The following example shows a fragment of the extracted TreeViewItem default Style. It misses other referenced resources in order to compact the example.
You can extract the complete Style using the XAML designer and then paste the Style for the TreeViewItem from below to replace the extracted Style of the TreeViewItem.
I have annotated the modified parts to help spotting the required modifications.

MainWindow.xanl.cs

partial class MainWindow : Window
{
  public static DataTemplate GetExtendedContentItemTemplate(DependencyObject attachingElement) 
    => (DataTemplate)attachingElement.GetValue(ExtendedContentItemTemplateProperty);

  public static void SetExtendedContentItemTemplate(DependencyObject attachingElement, DataTemplate value) 
    => attachingElement.SetValue(ExtendedContentItemTemplateProperty, value);

  public static readonly DependencyProperty ExtendedContentItemTemplateProperty = DependencyProperty.RegisterAttached(
    "ExtendedContentItemTemplate", 
    typeof(DataTemplate), 
    typeof(MainWindow), 
    new PropertyMetadata(default));
}

MainWindow.xaml

<Window>
  <Window.Resources>
    
    <!-- The example DataTemplate for the extended content -->
    <DataTemplate x:Key="ExtendedDataContentTemplate"
                  DataType="NestedContainer">
      <StackPanel>
        <TextBlock Text="{Binding ActionData}" />
        <TextBlock Text="{Binding Modifier}" />
      </StackPanel>
    </DataTemplate>

    <!-- 
         The fragment of the complete TreeViewItem style.
         The first setter that sets the attached 'ExtendedContentItemTemplate' property
         and the ControlTemplate that extends the layout to add the ContentControl 
         for the additional content are of special interest here.
    -->
    <Style TargetType="{x:Type TreeViewItem}">

      <!-- Assign the DataTemplate for the extended content to the attached property -->
      <Setter Property="local:MainWindow.ExtendedContentItemTemplate"
              Value="{StaticResource ExtendedDataContentTemplate}" />

      <Setter Property="Background"
              Value="Transparent" />
      <Setter Property="HorizontalContentAlignment"
              Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
      <Setter Property="VerticalContentAlignment"
              Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
      <Setter Property="Padding"
              Value="1,0,0,0" />
      <Setter Property="Foreground"
              Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
      <Setter Property="FocusVisualStyle"
              Value="{StaticResource TreeViewItemFocusVisual}" />
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type TreeViewItem}">
            <Grid>
              <Grid.ColumnDefinitions>
                <ColumnDefinition MinWidth="19"
                                  Width="Auto" />
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="*" />
              </Grid.ColumnDefinitions>
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto" /> <!-- Default header row -->
                <RowDefinition /> <!-- Default child items row -->
                <RowDefinition Height="Auto" /> <!-- New extra content row -->
              </Grid.RowDefinitions>
              <ToggleButton x:Name="Expander"
                            ClickMode="Press"
                            IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                            Style="{StaticResource ExpandCollapseToggleStyle}" />
              <Border x:Name="Bd"
                      Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}"
                      Grid.Column="1"
                      Padding="{TemplateBinding Padding}"
                      SnapsToDevicePixels="true">
                <ContentPresenter x:Name="PART_Header"
                                  ContentSource="Header"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
              </Border>
              <ItemsPresenter x:Name="ItemsHost"
                              Grid.Column="1"
                              Grid.ColumnSpan="2"
                              Grid.Row="1" />
    
              <!-- 
                   The host for the extra content below the child items.
                   For this purpose we have to introduce a third row to the Grid.
                   The Content is the data item itself (in this case 'NestedContainer').
                   The ContentTemplate binds to the attached property ExtendedContentItemTemplate 
                   that is set on the TreeViewItem via the current Style (see style setter above).
              --> 
              <ContentControl Grid.Row="2"
                              Grid.Column="1"
                              Content="{TemplateBinding DataContext}"
                              ContentTemplate="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:MainWindow.ExtendedContentItemTemplate)}" />
            </Grid>

            <ControlTemplate.Triggers>
              <Trigger Property="IsExpanded"
                       Value="false">
                <Setter Property="Visibility"
                        TargetName="ItemsHost"
                        Value="Collapsed" />
              </Trigger>
              <Trigger Property="HasItems"
                       Value="false">
                <Setter Property="Visibility"
                        TargetName="Expander"
                        Value="Hidden" />
              </Trigger>
              <Trigger Property="IsSelected"
                       Value="true">
                <Setter Property="Background"
                        TargetName="Bd"
                        Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
                <Setter Property="Foreground"
                        Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" />
              </Trigger>
              <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="IsSelected"
                             Value="true" />
                  <Condition Property="IsSelectionActive"
                             Value="false" />
                </MultiTrigger.Conditions>
                <Setter Property="Background"
                        TargetName="Bd"
                        Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}" />
                <Setter Property="Foreground"
                        Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}" />
              </MultiTrigger>
              <Trigger Property="IsEnabled"
                       Value="false">
                <Setter Property="Foreground"
                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <Style.Triggers>
        <Trigger Property="VirtualizingPanel.IsVirtualizing"
                 Value="true">
          <Setter Property="ItemsPanel">
            <Setter.Value>
              <ItemsPanelTemplate>
                <VirtualizingStackPanel />
              </ItemsPanelTemplate>
            </Setter.Value>
          </Setter>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>

  <TreeView ItemsSource="{Binding}">
    <TreeView.Resources>
      <HierarchicalDataTemplate DataType="NestedContainer"
                                ItemsSource="{Binding ChildContainers}">
        <TextBlock Text="{Binding XID}" />
      </HierarchicalDataTemplate>
    </TreeView.Resources>
  </TreeView>
</Window>

Csharp相关问答推荐

有没有办法把+02:00转换成TimeSpan?""

如何注销Microsoft帐户?

在.NET核心项目中创建Startup.cs比在Program.cs中注册服务好吗?

反序列化私有成员

如果设置了另一个属性,则Newtonsoft JSON忽略属性

如何在Cosmos SDK中控制超时、重试和重试之间的延迟?

.NET并发词典交换值

Polly重试URL复制值

EF核心新验证属性`DeniedValues`和`StringCompison`不起作用

记录类型';==运算符是否与实现IEquatable<;T&>;的类中的';equals&>方法执行等价比较?

如何从另一个类的列表中按ID取值

当我try 在与XAMP的MySQL服务器连接的ASP.NET核心应用程序中添加迁移时出现错误

将J数组转换为列表,只保留一个嵌套的JToken

序列化过程中的死循环

如何使用IHostedService添加数据种子方法

如何在单击按钮后多次异步更新标签

如何使用moq和xUnit对删除操作进行单元测试?

当我在Git中暂存文件更改时,它们会消失

Unity 3D-意外轴捕捉和未知力对脉冲react 行为的影响

C#、Visual Studio代码、调试器、错误处理变量请求.未知错误:0x80131502,