将XML数据绑定到WPF树形控件

3
我花费了很多时间来尝试将我的XML文件中的数据绑定到TreeView控件,但我不知道从哪里开始。我甚至尝试阅读StackOverflow上的WPF TreeView与Xml数据的双向绑定和Josh Smith在codeproject上的代码示例,但仍然无法理解如何入手!!!
我有一个XML文件,位于"C:\SPDependencies.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个回答

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";
    }
}

输出:

树形视图输出

如果您只想显示根节点下面的节点,请将XPath更改为:

XmlData.XPath = "/node/node";

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的文章。


我也对这个话题感兴趣。你的回答有什么遗漏吗?我无法显示任何数据...谢谢。 - Number8
我建议您创建一个新问题并发布您的代码,这样我们就可以看到问题所在了。 - Crippeoblade

1

我已经找到了一种方法,可以在不影响TreeView.DataContext的情况下完成这个操作。绑定很容易。Codebehind也很容易,但有一个小问题。

如果将XmlDataProvider绑定或分配给ItemsSource,则什么都得不到。它不是IEnumerable(虽然它是INotifyPropertyChanged),也没有隐式转换。你想要的是XmlDataProvider.Data,它被声明为Object,但我看到的是运行时类型为XmlDataCollection(它继承自ReadOnlyObservableCollection<XmlNode>)。

MVVM

绑定Data很容易。我不知道将XmlDataProvider放在您的视图模型中是否是纯粹的MVVM,也许不是。

视图模型:

public XmlDataProvider ViewModelXMLDataProp { ... }

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

完成了 - 除非您需要使用BindingXPath属性。如果是这样,您必须使用DataContext的技巧。您不能在同一个绑定上同时设置PathXPath

XmlDataProviderXPath属性执行相同的操作。如果您可以使用它,那就很好。

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

<TreeView
    ItemsSource="{Binding Source={StaticResource MyXmlDataProviderResource}}"
    ...
    />

但是这只适用于您提供静态资源的情况。下面的代码实际上会绑定到字符串 "ViewModelXMLDataProp",而不是查找 DataContext 中是否存在该属性。这样做是不好的。

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

也许你可以编写一个MarkupExtension来实现这个功能,但没有必要。

代码后台

你应该学习和使用MVVM,但事情总有很多原因,你不是来听布道的。

代码后台有点棘手。 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时,这仍然是一个问题。当Data属性最终被设置时,Binding仍然会挂起,并更新ItemsSource。但是在您的代码后台文件中对ItemsSource进行赋值并不会做任何事情。
与Stack Overflow上普遍流传的民间信仰相反,在以下代码中没有发生任何绑定,也没有以任何方式进行绑定:
//  NOT A BINDING
treeView.ItemsSource = someRandomCollectionOfStuff;

如果没有人创建System.Windows.Data.Bindingx:Bind的实例,那么它就不是绑定。这种区别很重要:“使用x的当前值”不是“无限期地更新y.x的未来值,每当y引发PropertyChanged时”。
您可以以编程方式创建Binding甚至处理PropertyChanged,但他们提供了一个更简单的选项。只需处理XmlDataProvider.DataChanged事件即可。
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;
}

这就完成了。你甚至可以保留该提供程序,加载新的XML,并使“DataChanged”事件保持树视图的最新状态。不过,这似乎是一种浪费精力的做法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接