【问题标题】:Generic classes don't bind to HierarchicalDataTemplate泛型类不绑定到 HierarchicalDataTemplate
【发布时间】:2012-12-10 16:04:43
【问题描述】:

我是 WPF 新手,所以可能会遗漏一些明显的东西,但无法在任何地方找到答案。

基本上,我正在构建一个以特定方式排序的自定义树集合,并且树的节点被键入到集合的类型。在TreeView 中进行测试时,HierarchicalDataTemplate 在节点是通用的情况下不起作用。如果它们不是通用的,那很好。

这里有一个简单的节点类来说明:

public class SimpleNode<T>
{
    private List<SimpleNode<T>> _children;
    private string _name;

    public SimpleNode(string name)
    {
        _name = name;
    }

    public List<SimpleNode<T>> Children
    {
        get
        {
            return _children;
        }
        set
        {
            _children = value;
        }
    }

    public string Name
    {
        get
        {
            return _name;
        }
    }
}

然后在 xaml 中:

HierarchicalDataTemplate DataType="{x:Type local:SimpleNode`1}" ItemsSource="{Binding Children}"

显然,附加到类型的 `1 是 SimpleNode 具有 1 个通用参数的结果。如果我剥离泛型类,HierarchicalDataTemplate 可以工作,我可以在TreeView 中查看树。有了泛型,它就不会这样做了。

有什么想法吗?

提前致谢。

【问题讨论】:

    标签: c# wpf treeview hierarchicaldatatemplate


    【解决方案1】:

    没有开箱即用的支持。但是您可以通过创建自己的支持泛型的DataTemplateSelector 来使其工作:

    public class OpenGenericTypeDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate SelectTemplate(object item,
                                                    DependencyObject container)
        {
            var element = container as FrameworkElement;
            if (item != null && element != null)
            {
                if (item.GetType().IsGenericType)
                {
                    var genericTypeDefinition = item.GetType()
                                                    .GetGenericTypeDefinition();
                    var key = new DataTemplateKey(genericTypeDefinition);
                    return element.TryFindResource(key) as DataTemplate;
                }
            }
    
            return null;
        }
    }
    

    你可以这样使用它:

    <UserControl.Resources>
      <OpenGenericTypeDataTemplateSelector x:Key="GenericTemplateSelector" />
    </UserControl.Resources>
    ...
    <TreeView ItemTemplateSelector="{StaticResource GenericTemplateSelector}" ...>
      <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type local:SimpleNode`1}"
                                  ItemsSource="{Binding Children}">
          ...
        </HierarchicalDataTemplate>
      </TreeView.Resources>
    

    这样做其实很简单:
    当您为某个类型创建 DataTemplate 时,该类型的名称将自动成为该模板的键。
    默认DataTemplateSelector 使用项目的类型作为查找值。但是泛型类的实例的类型是封闭的泛型类型,即具有指定泛型类型参数的类型。
    问题是:模板已为开放的泛型类型注册,即没有指定泛型类型参数。这就是为什么默认的 DataTemplateSelector 不会选择为开放泛型类型注册的 DataTemplates。
    我提供的实现通过简单地检查项目的类型来增加对开放泛型类型的支持。如果它是泛型的,我们会为自己获取开放的泛型类型(通过GetGenericTypeDefinition)并将其用作键。

    要真正使用这个选择器,我们必须告诉TreeView 它应该使用它。我们通过指定 ItemTemplateSelector 来做到这一点。

    【讨论】:

    • 非常感谢,我会看一下,看看我是否能弄清楚你在这里做了什么。同样为了快速解决方案,我发现了另一篇文章,它建议制作一个非泛型基类并在 WPF 中引用它——这似乎也有效。 [链接]stackoverflow.com/questions/6586528/…
    • @user1373164:我添加了一个解释这里发生了什么。当然,非泛型基类可以工作,但它只是解决标准 DataTemplateSelector 实现的缺点的一种解决方法,因此我不会推荐它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    相关资源
    最近更新 更多