wpf TreeView HierarchicalDataTemplate具有多个嵌套节点类型和潜在的“无限”级别

djmepvbi  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(131)

我有三门课。

public class ConfiguratorObjectViewModel
{
    public string Name { get; set; }
    
    public string Id { get; set; }
        
        public string ParentId { get; set; }
    
    public ObservableCollection<ConfiguratorAttributeViewModel> Attributes { get; set; } 
        
    public ObservableCollection<ConfiguratorObjectFamilyViewModel> Children { get; set; }   
}
public class ConfiguratorObjectFamilyViewModel
{
    public string Name { get; set; }
    
    public string Id { get; set; }
        
        public string ParentId { get; set; }
        
    public ObservableCollection<ConfiguratorObjectViewModel> ConfiguratorObjects { get; set; }  
}
public class ConfiguratorAttributeViewModel
{
    public string Name { get; set; }
    
    public string Id { get; set; }
        
    public string ParentId { get; set; }    
}

我希望得到一个TreeViewHierarchicalDataTemplate,它递归地构建一个潜在无限深度的树,这取决于可用的数据,例如

-Root(ConfiguratorObject)
    |-Family1(ConfiguratorObjectFamily)
        |-Object1(ConfiguratorObject)
        |-Object2(ConfiguratorObject)
            |-AnotherFamily(ConfiguratorObjectFamily)
                |-AnotherObject1(ConfiguratorObject)
                |-AnotherObject2(ConfiguratorObject)
    |-Family2(ConfiguratorObjectFamily)
    |-Famil3(ConfiguratorObjectFamily)

我试过这个,它起作用,但有限,因为有些值(水平)不会显示...

<TreeView ItemsSource="{Binding RootObject}" >
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
             <!--Root--> 
            <local:ConfiguratorObjectTreeItem  />
            
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate  ItemsSource="{Binding ConfiguratorObjects}">
                     <!--Children--> 
                    <local:ConfiguratorObjectTreeItem  />
                    
                    <HierarchicalDataTemplate.ItemTemplate>
                        <HierarchicalDataTemplate ItemsSource="{Binding Children}">
                             <!--Variants--> 
                            <local:ConfiguratorObjectTreeItem  />                                        

                        </HierarchicalDataTemplate>
                    </HierarchicalDataTemplate.ItemTemplate>
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>

</TreeView>

我尝试了上面提供的解决方案。该解决方案“有效”,但是是静态的-受限于树中显示的级别数量。我需要一个动态的解决方案。任何帮助将不胜感激!

编辑

我尝试了@BionicOCode建议,但只得到根节点

<TreeView ItemsSource="{Binding RootObject}" >
    <TreeView.Resources>
    
    <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectFamilyViewModel}" ItemsSource="{Binding Children}">
            <local:ConfiguratorObjectTreeItem  />
        </HierarchicalDataTemplate>
    
     <HierarchicalDataTemplate DataType="{x:Type local:ConfiguratorObjectViewModel}" ItemsSource="{Binding ConfiguratorObjects}" >
            <local:ConfiguratorObjectTreeItem  />
        </HierarchicalDataTemplate>   

    </TreeView.Resources>

</TreeView>
enyaitl3

enyaitl31#

必须将所有模板定义为隐式HierarchicalDataTemplate。这意味着您 * 必须 * 设置HierarchicalDataTemplate.DataType属性,并将没有显式键的模板添加到TreeView范围内的ResourceDictionary(例如TreeView.ResourcesApp.xaml)。
现在,当您为每个数据模型类型定义一个隐式HierarchicalDataTemplate(或DataTemplate,如果节点不能有或不允许有子节点)时,WPF将自动为树中的当前数据模型类型加载匹配模板。
或者定义一个DataTemplateSelector来显式地选择要为当前数据模型加载的模板。
下面的示例显示如何隐式定义数据树视觉外观,以允许具有动态树级别(深度和宽度/广度)和树组成的完全动态树结构。该树随机包含橙子、黄色和蓝色节点,这些节点被渲染为圆形、矩形和直线。

MainWindow.xaml.cs

private void OnLoaded(object sender, RoutedEventArgs e)
{
  var orange1 = new OrangeDataModel("Orange 1 (Root)");

  var yellow1 = new YellowDataModel("Yellow 1");
  orange1.Children.Add(yellow1);

  var blue1 = new BlueDataModel("Blue 1");
  orange1.Children.Add(blue1);

  var orange2 = new OrangeDataModel("Orange 2");
  var orange3 = new OrangeDataModel("Orange 3");
  blue1.Children.Add(orange2);
  blue1.Children.Add(orange3);

  var yellow2 = new YellowDataModel("Yellow 2");
  blue1.Children.Add(yellow2);

  var blue2 = new BlueDataModel("Blue 2");
  var blue3 = new BlueDataModel("Blue 3");
  yellow2.Children.Add(blue1);
  yellow2.Children.Add(blue3);
      
  var orange4 = new OrangeDataModel("Orange 4");
  yellow1.Children.Add(orange4);

  var root = new ObservableCollection<object> { orange1 };
  this.TreeView.ItemsSource = root;
}

MainWindow.xaml

<TreeView x:Name="TreeView">
  <TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type local:OrangeDataModel}"
                              ItemsSource="{Binding Yellows}">
      <Grid>
        <Ellipse Height="50"
                  Width="50"
                  Fill="DarkOrange" />
        <TextBlock Text="{Binding TextValue}" />
      </Grid>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type local:YellowDataModel}"
                              ItemsSource="{Binding Blues}">
      <Grid>
        <Rectangle Height="50"
                    Width="50"
                    Fill="Yellow" />
        <TextBlock Text="{Binding TextValue}" />
      </Grid>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type local:BlueDataModel}"
                              ItemsSource="{Binding Oranges}">
      <Grid>
        <Line X2="50"
              Stroke="Blue" />
        <TextBlock Text="{Binding TextValue}" />
      </Grid>
    </HierarchicalDataTemplate>
  </TreeView.Resources>
</TreeView>

OrangeDataModel.cs

public class OrangeDataModel : INotifyPropertyChanged
{
  public OrangeDataModel(string textValue)
  {
    this.TextValue = textValue;
    this.Yellows = new ObservableCollection<object>();
  }

  public string TextValue { get; set; }
  public ObservableCollection<object> Children { get; }
  public event PropertyChangedEventHandler? PropertyChanged;
}

YellowDataModel.cs

public class YellowDataModel : INotifyPropertyChanged
{
  public YellowDataModel(string textValue)
  {
    this.TextValue = textValue;
    this.Blues = new ObservableCollection<object>();
  }

  public string TextValue { get; set; }
  public ObservableCollection<object> Children{ get; }
  public event PropertyChangedEventHandler? PropertyChanged;
}

BlueDataModel.cs

public class BlueDataModel : INotifyPropertyChanged
{
  public BlueDataModel(string textValue)
  {
    this.TextValue = textValue;
    this.Oranges = new ObservableCollection<object>();
  }

  public string TextValue { get; set; }
  public ObservableCollection<object> Children{ get; }
  public event PropertyChangedEventHandler? PropertyChanged;
}

相关问题