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

问题描述:

我有一个XML需要将数据绑定到WPF TreeView。这里的XML可以有不同的结构。 TreeView应该是数据绑定通用的,足以加载任何层次结构的排列。然而,一个XAttribute节点上(称为标题)应数据绑定到TreeViewItem的标题文本不是节点名。要绑定如何将Xml属性绑定到Treeview节点,同时将XDocument绑定到WPF Treeview

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:

<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> 

加载XML到的XDocument并结合其XAML的代码隐藏到TreeView的

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

所以在XAML标记我们将Name绑定到TreeViewItem的头部。

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

但是,我想将其绑定到标题科,循环和页面的属性在上面的XML。我读过,绑定XDocument时不能使用XPath。但是必须有一种方法将标题属性绑定到TreeViewItem的标题文本。我尝试过使用@Title,[@ Title]等,但似乎没有任何工作。

这个thread on MSDN Forums有类似的讨论。

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

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

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

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

More @ this MSDN link

我认为,所有你需要做的是在你的XML创建为每个节点类型HierarchicalDataTemplate,你的XML其加载到XmlDataProvider,然后绑定到TreeView。电视与XDP协同工作来绑定数据,并沿着线路的某处找出您已定义的HDT并将其DataType与XML中节点的名称相匹配。 XPATH可能会随着数据类型的不同而发生变化,但保持灵活性是另一个问题。

例如,我有一个小正则表达式测试应用程序。它包括一个帮助系统,它基本上是树中列出的所有不同的正则表达式部分:类别和部分与描述,工具提示和其他东西。有关零件的数据存储为一个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> 

接下来,我创建HierarchicalDataTemplates在数据(同样,这一切是在应用程序的资源),每个节点类型:

<!-- Category data template --> 
<HierarchicalDataTemplate 
    DataType="Category" 
    ItemsSource="{Binding XPath=*}"> 
    <TextBlock 
     Focusable="False" 
     Text="{Binding [email protected]}" 
     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 [email protected]}" /> 
     <TextBlock 
      Text=" - " /> 
     <TextBlock 
      Text="{Binding [email protected]}" /> 
    </WrapPanel> 
</HierarchicalDataTemplate> 

最后,我只是约束树到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> 

而这一切,你必须做的。 TreeView和XmlDataProvider将负责为数据中的正确节点查找并使用正确的HDT's。所有这些中最难的部分是找出你的xpaths进行绑定。它可能会有点棘手,就像你的路径不正确,你最终会在树中没有任何东西,并且不会有任何错误(在WPF数据绑定中有增加错误报告的方法,但这是另一个问题) 。

+0

Thanks Will。你已经添加了一些非常好的信息。但我不喜欢XmlDataProvider的情况下,我正在与。虽然我的示例从文件加载XML,但实际上我直接将XDocument绑定到电视。尽管我找到了解决方案。将它作为答案发布。 – Vin 2008-10-26 17:04:08

+0

正如你在我的例子中看到的那样,使用XmlDataProvider可以让你将树的所有模板分解为HDT,从而大大简化你的xaml。您可以将XDocument合并到您的代码隐藏中,没有问题。但是,如果这对你有用,那么你就有更多的权力。 – Will 2008-10-26 18:30:53