【问题标题】:Add different types of childs to treeview将不同类型的孩子添加到树视图
【发布时间】:2016-10-19 23:24:28
【问题描述】:

我想在TreeView 中可视化Test 类的集合(来自模型程序集的POCO)。每个Test 实例都有一个ReadersGroups 的集合:

测试类伪代码

public class Test 
{
    // properties
   public  ObservableCollection<Reader> Readers { get; set; }
   public  ObservableCollection<Group> Groups { get; set; }
}

我想要什么

我的目标是像这样在TreeView 中可视化测试:

Test 1  
   |- Reader 1  
   |- Reader 2  
   |- Group 1   
   |- Group 2

Test 2  
   |- Reader 1  
   |- Group 4   
   |- Group 5

到目前为止我得到了什么

我可以使用 HierarchicalDataTemplate 向测试和读者展示

<HierarchicalDataTemplate DataType="{x:Type model:Test}" ItemsSource="{Binding Readers}">
    <TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate> 

基本上我想告诉TreeView,“嘿,我的测试类中有另一个带有另一个模板的子项源,使用它!”。

我尝试使用读者和组的CompositeCollection,但由于我不想更改测试类(它是生成的代码)而卡住了。

【问题讨论】:

  • ReaderGroup 共享任何基础吗?如果是这样,您可以公开基本类型的 Collection,然后在 XAML 中使用不同的 DataTemplates 对每个具体类型(ReaderGroup)进行不同的处理
  • [基本上我想告诉 TreeView,“嘿,我的测试类中有另一个带有另一个模板的子项源,使用它!”]。这就是为什么他们称之为 MVVM 并创建视图模型以方便的形式(例如 CompositeCollection )为视图提供数据。
  • @ASh:您建议将测试类转换为对视图更方便的东西,例如具有读者和组的复合集合的 TestViewModel。对吗?
  • @nabulke,不完全是。我将保留 Test (model) 类,但为其添加 TestViewModel,并确保 TestViewModel 具有可用作 ItemsSource 的 Readers 和 Groups 的集合属性
  • @nabulke,或者其他方式:在 xaml 中定义 CompositeCollection 并为 Readers 和 Groups 使用两个数据绑定 CollectionContainers

标签: c# wpf treeview


【解决方案1】:

创建一个Converter 并在您的HierarchicalDataTemplate.ItemsSource 中使用它。

转换器:

public class ReadersGroupsCombineConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<Reader> readers = (value as Test).Readers;
        ObservableCollection<Group> groups = (value as Test).Groups;

        ObservableCollection<object> readersGroups = new ObservableCollection<object>();
        foreach (Reader reader in readers)
            readersGroups.Add(reader);

        foreach (Group group in groups)
            readersGroups.Add(group);

        return readersGroups;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

XAML:

    <HierarchicalDataTemplate x:Key="HDTReaderGroups" ItemsSource="{Binding ., Converter={StaticResource ReaderGroupsCombineCnvKey}}">
        <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}"/>
            </DataTemplate>
        </HierarchicalDataTemplate.ItemTemplate>
        <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>

【讨论】:

    【解决方案2】:

    我过去所做的并建议您做的是为您想要在树视图中表示的每种类型创建一个包装器对象。您可以在视图模型中初始化该结构。设置好所有对象后,您可以这样做:

    <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:TestNode}">
    <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
    

    现在是孩子们的模板:

    <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:ReaderNode}">
        <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
    
    <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type Model:GroupNode}">
        <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>
    

    这样您就可以为您正在建模的每种类型的对象创建一个模板。

    正如我之前所说,我建议您这样做,因为绑定到未实现 INotifyPropertyChanged 的​​对象会泄漏内存,并且通常 POCO 和 DTO 不会实现它。你可以在这里看到更多:https://support.microsoft.com/en-us/kb/938416

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-03
      • 1970-01-01
      • 1970-01-01
      • 2015-01-07
      • 1970-01-01
      • 2012-07-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多