C# 如何将 Xml 属性绑定到 Treeview 节点,同时将 XDocument 数据绑定到 WPF Treeview

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/238196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:21:01  来源:igfitidea点击:

How to bind Xml Attribute to Treeview nodes, while databinding XDocument to WPF Treeview

c#wpfdata-bindingxamltreeview

提问by Vin

I have an XML that needs to be databound to a WPF TreeView. Here the XML can have different structure. The TreeView should be databound generic enough to load any permutation of hierarchy. However an XAttributeon the nodes (called Title) should be databound to the TreeViewItem's header textand not the nodename.

我有一个需要数据绑定到WPF TreeView的 XML 。这里的 XML 可以有不同的结构。TreeView 应该是数据绑定通用的,足以加载层次结构的任何排列。但是,节点上的XAttribute(称为Title)应该数据绑定到 TreeViewItem 的标题文本,不是 nodename

XML to be bound:

要绑定的 XML:

<Wizard>
  <Section Title="Home">
    <Loop Title="Income Loop">
      <Page Title="Employer Income"/>
      <Page Title="Parttime Job Income"/>
      <Page Title="Self employment Income"/>
    </Loop>
  </Section>
  <Section Title="Deductions">
    <Loop Title="Deductions Loop">
      <Page Title="Travel spending"/>
      <Page Title="Charity spending"/>
      <Page Title="Dependents"/>
    </Loop>
  </Section>
</Wizard>

XAML:

XAML:

<Window x:Class="Wpf.DataBinding.TreeViewer"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Wpf.DataBinding"
    Title="TreeViewer" Height="300" Width="300">
    <Window.Resources>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Elements}" x:Key="TVTemplate">
            <TreeViewItem Header="{Binding Path=Name}"/>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <StackPanel>
        <TreeView x:Name="_treeView" Style="{StaticResource TVallExpanded}"
                ItemsSource="{Binding Path=Root.Elements}"
                ItemTemplate="{StaticResource TVTemplate}" />
    </StackPanel>
</Window>

XAML's codebehind that loads XML to XDocument and binds it to TreeView

XAML 的代码隐藏将 XML 加载到 XDocument 并将其绑定到 TreeView

public partial class TreeViewer : Window
{
    public TreeViewer()
    {
        InitializeComponent();
        XDocument doc = XDocument.Parse(File.ReadAllText(@"C:\MyWizard.xml"));
        _treeView.DataContext = doc;
    }
}

So in the XAML markup we are binding Name to TreeViewItem's header.

因此,在 XAML 标记中,我们将 Name 绑定到 TreeViewItem 的标头。

<TreeViewItem Header="{Binding Path=Name}"/>

However, I want to bind it to Titleattribute of Section, Loop and Page in the Xml above. I read that it's not possible to use XPath while binding XDocument. But there has to be a way to bind the Titleattribute to TreeViewItem's Header text. I tried using @Title, .[@Title] etc. But none seemed to work.

但是,我想将它绑定到上面 Xml 中 Section、Loop 和 Page 的Title属性。我读到在绑定 XDocument 时无法使用 XPath。但是必须有一种方法将Title属性绑定到 TreeViewItem 的 Header 文本。我尝试使用@Title、.[@Title] 等。但似乎没有任何效果。

This thread on MSDN Forumshas a similar discussion.

MSDN 论坛上的这个帖子也有类似的讨论。

Any pointers would be greatly helpful.

任何指针都会非常有帮助。

采纳答案by Vin

Hurrah !!! I figured out how to bind XAttribute. It is not intuitive and it's not easily imaginable. But here is how it can be done.

万岁!!!我想出了如何绑定 XAttribute。它不直观,也不容易想象。但这是如何做到的。

<TreeViewItem Header="{Binding Path=Attribute[Title].Value}"/>

It is hard to imagine that Title can directly be used in square braces.

很难想象 Title 可以直接用在方括号中。

More @ this MSDN link

更多@这个MSDN链接

回答by Vin

I think all you need to do is create a HierarchicalDataTemplatefor each node type in your XML, load your xml it into an XmlDataProvider, and then bind thatto the TreeView. The TV works with the XDP to bind data, and somewhere along the line they figure out what HDTs you have defined and match their DataType to the names of the nodes in your XML. You might have some issues with your XPATHs changing with the different types of data, but keeping those flexible is another question.

我认为您需要做的就是为 XML 中的每个节点类型创建一个HierarchicalDataTemplate,将您的 xml 加载到XmlDataProvider 中,然后将绑定到 TreeView。电视与 XDP 一起绑定数据,并且在此过程中,它们会找出您定义的 HDT,并将它们的数据类型与 XML 中的节点名称相匹配。您的 XPATH 可能会随着不同类型的数据的变化而发生一些问题,但保持这些灵活性是另一个问题。

For example, I have a little regex test app. It includes a help system which is essentially all the different regex parts listed in a tree: Categories and parts with descriptions, tooltips, and other stuff. The data about the parts is stored as an xml data source. Since its static, I just created a static resource with the application's resources:

例如,我有一个小的正则表达式测试应用程序。它包括一个帮助系统,该系统本质上是树中列出的所有不同的正则表达式部分:类别和部分以及描述、工具提示和其他内容。有关零件的数据存储为 xml 数据源。由于它是静态的,我只是用应用程序的资源创建了一个静态资源:

<XmlDataProvider
    x:Key="rxPartData"
    XPath="RegexParts">
    <x:XData>
        <RegexParts
            xmlns="">
            <Category
                Name="Character class"
                ToolTip="Sets of characters used in matching">
                <RegexPart
                    Regex="[%]"
                    Hint="Positive character group"
                    ToolTip="Matches any character in the specified group (replace % with one or more characters)" />
                <!-- yadda -->
            </Category>
        </RegexParts>
    </x:XData>
</XmlDataProvider>

Next, I created HierarchicalDataTemplatesfor each node type in the data (again, all of this is in the application's resources):

接下来,我为数据中的每个节点类型创建了HierarchicalDataTemplates(同样,所有这些都在应用程序的资源中):

<!-- Category data template -->
<HierarchicalDataTemplate
    DataType="Category"
    ItemsSource="{Binding XPath=*}">
    <TextBlock
        Focusable="False"
        Text="{Binding XPath=@Name}"
        ToolTip="{StaticResource CategoryTooltip}"
        ToolTipService.InitialShowDelay="0"
        ToolTipService.ShowDuration="{x:Static sys:Int32.MaxValue}"
        ToolTipService.HasDropShadow="True" />
</HierarchicalDataTemplate>
<!-- RegexPart data template -->
<HierarchicalDataTemplate
    DataType="RegexPart"
    ItemsSource="{Binding XPath=*}">
    <WrapPanel
        Focusable="False"
        ToolTip="{StaticResource RegexPartTooltip}"
        ToolTipService.InitialShowDelay="0"
        ToolTipService.ShowDuration="{x:Static sys:Int32.MaxValue}"
        ToolTipService.HasDropShadow="True">
        <TextBlock
            Text="{Binding XPath=@Regex}" />
        <TextBlock
            Text=" - " />
        <TextBlock
            Text="{Binding XPath=@Hint}" />
    </WrapPanel>
</HierarchicalDataTemplate>

Lastly, I just bound the tree to the XmlDataProvider:

最后,我只是将树绑定到 XmlDataProvider:

<TreeView
  Name="_regexParts"
  DockPanel.Dock="Top"
  SelectedItemChanged="RegexParts_SelectedItemChanged"
  ItemsSource="{Binding Source={StaticResource rxPartData}, XPath=/RegexParts/Category}"
  ToolTip="Click the + to expand a category; click a part to insert it">
</TreeView>

And that's all you have to do. The TreeView and the XmlDataProviderwill take care of finding and using the correct HDT'sfor the correct nodes in the data. The hardest part of all this is figuring out your xpaths for binding. It can get a little tricky, as if your paths are incorrect, you'll end up getting nothing in the tree and there won't be any errors (there are ways to increase error reporting in databinding in WPF, but that's another question).

这就是你所要做的。TreeView 和XmlDataProvider将负责为数据中的正确节点查找和使用正确的HDT。所有这一切中最困难的部分是找出用于绑定的 xpath。它可能会有点棘手,就好像您的路径不正确一样,您最终将在树中一无所获,并且不会出现任何错误(有一些方法可以增加 WPF 中数据绑定中的错误报告,但这是另一个问题) .