65.9K
CodeProject 正在变化。 阅读更多。
Home

高级 WPF 树形视图,多级绑定(代码隐藏 - 无 XAML!)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2017年12月21日

CPOL

2分钟阅读

viewsIcon

15344

downloadIcon

709

演示如何使用 C# 代码隐藏方式,在不使用 XAML 的情况下创建具有多级 HierarchicalDataTemplate 的 WPF 树形视图,并使用 MVVM 进行数据绑定。

引言

通常情况下,您应该**几乎总是使用 XAML** 来创建 WPF UI。但是,本文的目的是展示在不使用 XAML 的情况下,在 WPF 中创建 UI 的代码隐藏方式。在动态 UI 创建和消除复杂的 XAML 绑定方面,这种方式可以灵活而强大。

代码隐藏方法是一种高级概念。即使您可能永远不需要使用它,理解它将帮助您更好地理解 WPF 的工作原理。查尔斯·佩茨奥德写了一本很棒的 WPF 书,书中使用了大量的代码隐藏。

仍然感兴趣吗?让我们继续。

背景

在网上有 WPF TreeView 的示例,但它们大多是基于 XAML 的。例如

我使用 TreeView + HierarchicalDataTemplate 与多级绑定,因为它是在 XAML 绑定主题中最容易被误解的部分之一。我在这里不讨论 MVVM,因为网上可以找到大量相关信息。显然,本文的目标是面向中级和高级 WPF 用户。

Using the Code

启动时,应用程序看起来如下。它是一个 4 级 TreeView,根节点位于第 0 级。每个级别的节点都有自己的 HierarchicalDataTemplate

请注意,该项目解决方案中**没有.xaml 文件**

每个级别的节点都有一个 ViewModel 用于数据绑定。例如,C# 类 Level2NodeViewModel 用于数据绑定第 2 级节点,包含:箭头图像 + 文本 + 搜索图像 + 超链接

上述元素被包装在一个以编程方式创建的 StackPanel

private FrameworkElementFactory BuildLevel2NodeVisual()
{
    var stackPanelFactory = CreateStackPanelFactory(Orientation.Horizontal, new Thickness(4, 4, 5, 2));
    AppendImageBinding(stackPanelFactory, "NodeImagePath");
    AppendTextBlockBinding(stackPanelFactory, "Name");
    // Bind SearchImagePath with Level2NodeViewModel
    AppendImageBinding(stackPanelFactory, "SearchImagePath", new Thickness(10, 0, 0, 0));
    AppendHyperlinkBinding(stackPanelFactory, "Search with Amazon.com", Colors.MediumOrchid,
                            "AmazonSearchCommand", "AmazonSearchUrl", new Thickness(5, 0, 0, 0));
    return stackPanelFactory;
}

以下函数确定如何为任何级别创建“节点视觉”HierarchicalDataTemplate

private HierarchicalDataTemplate BuildLevelNodeDataTemplate(int level = int.MaxValue)
{
    FrameworkElementFactory levelNodeElementFactory;
    switch (level)
    {
        case 0: levelNodeElementFactory = BuildRootNodeVisual(); break;
        case 1: levelNodeElementFactory = BuildLevel1NodeVisual(); break;
        case 2: levelNodeElementFactory = BuildLevel2NodeVisual(); break;
        case 3: levelNodeElementFactory = BuildLevel3NodeVisual(); break;
        default: levelNodeElementFactory = BuildLevelNodeBasicVisual(); break;
    }
 
    var levelNodeDataTemplate = new HierarchicalDataTemplate
    {
        ItemsSource = new Binding("ChildNodes"),
        VisualTree = levelNodeElementFactory
    };
    return levelNodeDataTemplate;
}

在运行时,技巧是动态地为它的级别节点选择正确的 ViewModel

public class NodeDataTemplateSelector : DataTemplateSelector
{
    ....
 
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate dataTemplate;
        if (item == null)
            dataTemplate = base.SelectTemplate(null, container);
        else if (item is RootNodeViewModel)
            dataTemplate = LevelNodeDateTemplateOrDefault(0);
        else if (item is Level1NodeViewModel)
            dataTemplate = LevelNodeDateTemplateOrDefault(1);
        else if (item is Level2NodeViewModel)
            dataTemplate = LevelNodeDateTemplateOrDefault(2);
        else if (item is Level3NodeViewModel)
            dataTemplate = LevelNodeDateTemplateOrDefault(3);
        else
            dataTemplate = _defaultLevelNodeDataTemplate;
        return dataTemplate;
    }
}

结论

我使用了 Visual Studio 2015 和 C# 6.0 语法。如果您使用预 VS2015 编译应用程序,您将需要修复 C# 6.0 语法错误。这很容易做到,并且网上有相关信息。

© . All rights reserved.