将XML数据绑定到WPF树视图控件

时间:2009-04-03 14:45:42

标签: wpf treeview

我花了很多时间试图弄清楚如何将我的XML文件中的数据绑定到TreeView控件,但我不知道从哪里开始。我甚至尝试在codeproject上查看Two-way binding of Xml data to the WPF TreeView和Josh Smith的代码示例,但仍然无法理解如何开始!!!

我在文件“C:\ SPDependencies.xml”中有XML(如果需要,我可以更改格式)!!!:

  <node type="SPDependencies" Name="SPDependencies">
        <node type="StoredProc" Name="SP1">
                <node type="OperationType" Name="Type1">
                        <node type="TableName" Name="Table1"/>
                        <node type="TableName" Name="Table2"/>
                </node>
                <node type="OperationType" Name="Type2">
                         <node type="TableName" Name="Table1"/>
                        <node type="TableName" Name="Table2"/>
                </node>
                 .....
        </node>
        <node type="StoredProc" Name="SP2">
              <node type="OperationType" Name="Type1">
              ...
              ...
        </node>
</node>

我需要以下列格式在Treeview控件中显示它:

<SP1>
   <Type1>
      <Table1>
      <Table2>
      <Table3>
   <Type2>
      <Table1>
      <Table2>
      <Table3>
<SP2>
    <Type1>
........

谢谢, ABHI。

3 个答案:

答案 0 :(得分:5)

给出以下xml文件:

<node type="SPDependencies" Name="SPDependencies">
  <node type="StoredProc" Name="SP1">
    <node type="OperationType" Name="Type1">
      <node type="TableName" Name="Table1"/>
    </node>
    <node type="OperationType" Name="Type2">
      <node type="TableName" Name="Table1"/>
    </node>
  </node>
  <node type="StoredProc" Name="SP2">
    <node type="OperationType" Name="Type1">
    </node>
  </node>
</node>

查看:

<Window x:Class="Tree.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Tree"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <Window.Resources>
        <HierarchicalDataTemplate x:Key="template">
            <TextBlock Text="{Binding XPath=@Name}" />
            <HierarchicalDataTemplate.ItemsSource>
                <Binding XPath="node" />
            </HierarchicalDataTemplate.ItemsSource>
        </HierarchicalDataTemplate>
    </Window.Resources>
    <Grid DataContext="{Binding Path=XmlData}">
        <TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource template}">
        </TreeView>
    </Grid>
</Window>

查看型号:

public class ViewModel
{
    public XmlDataProvider XmlData { get; set; }

    public ViewModel()
    {
        XmlData = new XmlDataProvider();
        XmlData.Source = new Uri(@"C:\input.xml");
        XmlData.XPath = "node";
    }
}

<强>输出:

tree view output

如果您只想在根目录下显示 节点,只需将XPath更改为:

XmlData.XPath = "/node/node";

答案 1 :(得分:3)

继承树:

<Window.Resources>
    <HierarchicalDataTemplate DataType="node"
                              ItemsSource="{Binding XPath=node}">
        <TextBox Width="Auto"
                 Text="{Binding XPath=@Name, UpdateSourceTrigger=PropertyChanged}" />
    </HierarchicalDataTemplate>

    <XmlDataProvider
        x:Key="xmlDataProvider"
        XPath="node" Source="C:\Data.XML">
    </XmlDataProvider>
</Window.Resources>
<Grid>
    <StackPanel>
        <Button Click="Button_Click">Save</Button>
            <TreeView
                Width="Auto"
                Height="Auto"
                Name="treeview"
                ItemsSource="{Binding Source={StaticResource xmlDataProvider}, XPath=.}"/>
     </StackPanel>
</Grid>

我添加了一个简单的按钮来保存更改。所以对于你背后的代码中的Button_Click方法:

XmlDataProvider dataProvider = this.FindResource("xmlDataProvider") as XmlDataProvider;
dataProvider.Document.Save(dataProvider.Source.LocalPath);

有关数据绑定和WPF的文章,请参阅here

答案 2 :(得分:1)

我已经找到了如何在不踩TreeView.DataContext的情况下做到这一点。绑定很容易。 Codebehind几乎一样容易,但有一点点问题。

如果绑定XmlDataProviderItemsSource,则不会得到任何结果。它不是IEnumerable(虽然它是INotifyPropertyChanged)并且没有隐式转换。你想要的是XmlDataProvider.Data,它被声明为Object,但我看到了XmlDataCollection的运行时类型(继承自ReadOnlyObservableCollection<XmlNode>)。

MVVM

绑定Data很简单。我不知道将XmlDataProvider放在你的视图模型中是不是纯粹的MVVM,也许不是。

视图模型:

public XmlDataProvider ViewModelXMLDataProp { ... }

XAML

<TreeView
    ItemsSource="{Binding ViewModelXMLDataProp.Data}"
    ...
    />

完成 - 即,除非您需要使用XPath的{​​{1}}属性。如果您这样做,则必须使用Binding kludge。您无法在同一个绑定上同时设置DataContextPath

XPath的XPath属性做同样的事情。如果你可以使用它,那你很好。

您认为XmlDataProvider会起作用,因为当您的Binding.Source是静态资源时,它会起作用。当XmlDataProviderBinding.SourceDataSourceProvider未指定时,Path默认为Path

Data

...但是这样可行,因为你给它一个静态资源。以下实际上绑定到字符串<TreeView ItemsSource="{Binding Source={StaticResource MyXmlDataProviderResource}}" ... /> ,而不是通过该名称查找"ViewModelXMLDataProp"属性。那不好。

DataContext

也许你可以写一个<TreeView ItemsSource="{Binding Source=ViewModelXMLDataProp}" ... /> 来做那个工作,但是没有必要。

代码隐藏

你应该学习和使用MVVM,但事情发生的原因很多,你没有来这里讲道。

Codebehind有点棘手。 MarkupExtension只需要您提供的对象必须实现TreeView.ItemsSource,因此将System.Collections.IEnumerable强制转换为provider.Data并且不必担心确切的运行时类型。

现在这里是问题:System.Collections.IEnumerable是异步填充的。

XmlDataProvider.Data

即使我创建protected void LoadXML(String path) { var provider = new XmlDataProvider() { Source = new Uri(path, UriKind.Absolute), XPath = "./*" }; // FAIL: provider.Data is still null treeView.ItemsSource = (IEnumerable)provider.Data; } ,致电XmlDocument并将文档分配给XmlDocument.Load(),我发现这也是一个问题。当XmlDataProvider.Document属性最终设置完成后,Binding仍然会闲置,然后它会更新Data。但是在代码隐藏文件中对ItemsSource的赋值没有这样的事情。

与Stack Overflow中无处不在的民间信仰相反,在下面的代码中没有任何约束发生,并且在任何意义上都没有任何约束:

ItemsSource

如果没有人创建// NOT A BINDING treeView.ItemsSource = someRandomCollectionOfStuff; System.Windows.Data.Binding的实例,则不是绑定。这种区别很重要:“使用x:Bind的当前值”与“每次x提升y.x”时“使用y的未来值无限更新”概念不同。

您可以通过编程方式创建PropertyChanged或甚至处理Binding,但他们继续为您提供了一个更简单的选项。只需处理PropertyChanged事件即可。

XmlDataProvider.DataChanged

就是这样。您甚至可以保留该提供程序,在其中加载新的XML,并使protected void LoadXML(String path) { var provider = new XmlDataProvider() { Source = new Uri(path, UriKind.Absolute), XPath = "./*" }; provider.DataChanged += (s,e) => treeView.ItemsSource = (IEnumerable)provider.Data; } 事件保持树视图最新。虽然看起来像是浪费精力。