【问题标题】:WPF, TreeView, Bind to properties inside object in CollectionWPF,TreeView,绑定到集合中对象内的属性
【发布时间】:2016-01-01 13:19:45
【问题描述】:

这可能不是那么难,但我越来越糊涂了。

我想在我的视图中显示一个 TreeView,但我无法正确绑定数据。

TemplateFamilyList 集合是根对象。它将包含 TemplateFamily 对象的列表。这些 TemplateFamily 对象中的每一个都将包含一个 Template 对象和一个 TemplateParameter 对象列表,称为 TemplateParameterMembers。实际的 Template 类和实际的 TemplateParameter 类都具有 Name 属性以及其他属性。

所以,在我的 ViewModel 类中,我有这个填充集合的方法:

 public void LoadTemplateTree()
    {
        TemplateFamilyList = new ObservableCollection<TemplateFamily>();

        List<Template> templateList = BuilderService.GetAllTemplates();
        List<TemplateParameter> templatesParametersList;

        foreach (Template template in templateList)
        {
            templatesParametersList = BuilderService.GetATemplatesParameters(template.TemplateID);
            TemplateFamilyList.Add(new TemplateFamily(template, new ObservableCollection<TemplateParameter>(templatesParametersList)));              
        }
    }

这里是 TemplateFamily 类:

 public class TemplateFamily
{
    public Template Template { get; set; }

    public ObservableCollection<TemplateParameter> TemplateParameterMembers { get; set; }

    public TemplateFamily(Template aTemplate, ObservableCollection<TemplateParameter> templatesParameters)
    {
        Template = aTemplate;
        TemplateParameterMembers = templatesParameters;
    }
}

我想要的是一个 TreeView,例如:

  1. NameOfTemplateA
  2. NameOfTemplateB

    • NameOfTemplateParameterB1
    • NameOfTemplateParameterB2

等等

在我的 XAML 中我有这个:(但它不起作用,它提供了一些只有箭头但没有名称的空白树视图)。

<TabItem Header="Template Files" Height="22" VerticalAlignment="Top">
            <TreeView Height="Auto" Name="treeView1" Width="Auto" ItemsSource="{Binding TemplateFamilyList}">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding TemplateParameterMembers}" >
                        <TextBlock Text="{Binding Path=Name}" Margin="2" ></TextBlock>
                    </HierarchicalDataTemplate >
                </TreeView.ItemTemplate>
            </TreeView>
        </TabItem>

ViewModel 使用 ViewModelLocator 绑定到 View,在其他情况下也可以正常工作。我知道如果我绑定到 TemplateFamilyList,它将获得正确的对象,我只是不知道如何显示该列表中每个 TemplateFamily 的名称(应该是 TemplateFamily 对象的 Template 属性的 Name 属性)和那么对于树中的下一层,如果有 TemplateParameterMembers 列表,如何显示 TemplateParameterMembers 集合中每个项目的 TemplateParameter 属性的 Name 属性。

我想我可以尝试在 TemplateFamily 类中使​​用另一个属性 Name,并在构造函数中简单地复制 Template 的 Name 属性,例如:

public TemplateFamily(Template aTemplate, ObservableCollection<TemplateParameter> templatesParameters)
    {
        Template = aTemplate;
        Name = aTemplate.Name;
        TemplateParameterMembers = templatesParameters;
    }

但我不喜欢这种方法,此外,我没有一个特殊的“容器”类来收集 TemplateParameters,所以我仍然需要以某种方式向下钻取并获取 TemplateParameter 中的 Name 属性TemplateParameterMembers 集合的每一项。

我看到了这个post 似乎在答案中,Gishu 使用了 DataType 属性,例如:

DataType="{x:Type local:Group}

在 OP 帖子中定义的本地命名空间为:

xmlns:local="clr-namespace:TaskManager.Domain;assembly=TaskManager.Domain"

但是,就我而言,Template 和 TemplateParameter 类是我模型的一部分,它们甚至与 ViewModel 和 View 不在同一个项目中。 就我的本地命名空间而言,我有这个:

xmlns:local="clr-namespace:S.VisualStudioExtension"           
         local:ViewModelLocator.AutoWireViewModel="True"

然后我是否应该为 Template 和 TemplateParameter 类添加一个命名空间,例如:

xmlns:domain="clr-namespace:S.ModelDomain" 

并尝试在 DataType 属性中使用它?

我还怀疑我的 XAML 有问题,也许我应该有另一个 Hierarchical DataTemplate?

【问题讨论】:

    标签: c# wpf xaml mvvm treeview


    【解决方案1】:

    在这种情况下,最好和最通用的(在我看来)解决方案是为将在树中呈现的每种类型的项目定义一个模板,并将它们放入树的资源字典中。每个模板都应使用DataType 属性与相应的项目类型相关联。这样,将自动选择合适的模板来根据其类型呈现每个项目。假设您的 TemplateParameter 类是在命名空间 S.ModelDomain 中名为 S.ModelDomain 的项目中定义的,并且 local 前缀在您的 XAML 中正确定义,这应该会给您预期的结果(我冒昧地剥离了您的XAML 的无关属性):

    <TreeView xmlns:models="clr-namespace:S.ModelDomain;assembly=S.ModelDomain"
              ItemsSource="{Binding TemplateFamilyList}">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type local:TemplateFamily}"
                                      ItemsSource="{Binding TemplateParameterMembers}" >
                <TextBlock Text="{Binding Template.Name}" />
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type models:TemplateParameter}">
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
    

    通常的做法是在 XAML 的根元素上定义命名空间映射(通常是 WindowUserControl)。在此处查看更多信息:XAML Namespaces and Namespace Mapping for WPF XAML

    请注意,尽管模板已放入资源字典,但并未指定 x:Key 参数。在自动模板选择过程中需要考虑模板。这种模板称为隐式模板。这是一个有用的链接:Data Templating Overview

    【讨论】:

      最近更新 更多