Xml 数据到 WPF TreeView 的双向绑定 [英] Two-way binding of Xml data to the WPF TreeView

查看:30
本文介绍了Xml 数据到 WPF TreeView 的双向绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 WPF 作为表示层重写我的 ForestPad 应用程序.在 WinForms 中,我以编程方式填充每个节点,但如果可能,我想利用 WPF 的数据绑定功能.

I am attempting to rewrite my ForestPad application utilizing WPF for the presentation layer. In WinForms, I am populating each node programmatically but I would like to take advantage of the databinding capabilities of WPF, if possible.

一般来说,将 WPF TreeView 双向数据绑定到 Xml 文档的最佳方法是什么?

In general, what is the best way to two-way databind the WPF TreeView to an Xml document?

通用解决方案很好,但作为参考,我尝试绑定的 Xml 文档的结构如下所示:

A generic solution is fine but for reference, the structure of the Xml document that I am trying to bind to looks like this:

<?xml version="1.0" encoding="utf-8"?>
<forestPad
    guid="6c9325de-dfbe-4878-9d91-1a9f1a7696b0"
    created="5/14/2004 1:05:10 AM"
    updated="5/14/2004 1:07:41 AM">
<forest 
    name="A forest node"
    guid="b441a196-7468-47c8-a010-7ff83429a37b"
    created="01/01/2003 1:00:00 AM"
    updated="5/14/2004 1:06:15 AM">
    <data>
    <![CDATA[A forest node
        This is the text of the forest node.]]>
    </data>
    <tree
        name="A tree node"
        guid="768eae66-e9df-4999-b950-01fa9be1a5cf"
        created="5/14/2004 1:05:38 AM"
        updated="5/14/2004 1:06:11 AM">
        <data>
        <![CDATA[A tree node
            This is the text of the tree node.]]>
        </data>
        <branch
            name="A branch node"
            guid="be4b0993-d4e4-4249-8aa5-fa9c940ae2be"
            created="5/14/2004 1:06:00 AM"
            updated="5/14/2004 1:06:24 AM">
            <data>
            <![CDATA[A branch node
                This is the text of the branch node.]]></data>
                <leaf
                name="A leaf node"
                guid="9c76ff4e-3ae2-450e-b1d2-232b687214aa"
                created="5/14/2004 1:06:26 AM"
                updated="5/14/2004 1:06:38 AM">
                <data>
                <![CDATA[A leaf node
                    This is the text of the leaf node.]]>
                </data>
            </leaf>
        </branch>
    </tree>
</forest>
</forestPad>

推荐答案

好吧,如果您的元素层次结构更像...

Well, it would be easier if your element hierarchy was more like...

<node type="forest">
    <node type="tree">
        ...

...而不是您当前的架构.

...rather than your current schema.

按原样,您将需要 4 个 HierarchicalDataTemplate,每个分层元素(包括根)一个,一个 DataTemplate 用于 leaf元素:

As-is, you'll need 4 HierarchicalDataTemplates, one for each hierarchical element including the root, and one DataTemplate for leaf elements:

<Window.Resources>
    <HierarchicalDataTemplate
        DataType="forestPad"
        ItemsSource="{Binding XPath=forest}">
        <TextBlock
            Text="a forestpad" />
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate
        DataType="forest"
        ItemsSource="{Binding XPath=tree}">
        <TextBox
            Text="{Binding XPath=data}" />
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate
        DataType="tree"
        ItemsSource="{Binding XPath=branch}">
        <TextBox
            Text="{Binding XPath=data}" />
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate
        DataType="branch"
        ItemsSource="{Binding XPath=leaf}">
        <TextBox
            Text="{Binding XPath=data}" />
    </HierarchicalDataTemplate>
    <DataTemplate
        DataType="leaf">
        <TextBox
            Text="{Binding XPath=data}" />
    </DataTemplate>

    <XmlDataProvider
        x:Key="dataxml"
        XPath="forestPad" Source="D:fp.xml">
    </XmlDataProvider>
</Window.Resources>

您可以改为以编程方式设置 XmlDataProviderSource:

You can instead set the Source of the XmlDataProvider programmatically:

dp = this.FindResource( "dataxml" ) as XmlDataProvider;
dp.Source = new Uri( @"D:fp.xml" );

此外,重新保存您的编辑就像这样简单:

Also, re-saving your edits is as easy as this:

dp.Document.Save( dp.Source.LocalPath );

TreeView 本身需要一个 Name 和一个 ItemsSource 绑定到 XmlDataProvider:

The TreeView itself needs a Name and an ItemsSource bonded to the XmlDataProvider:

<TreeView
    Name="treeview"
    ItemsSource="{Binding Source={StaticResource dataxml}, XPath=.}">

在这个例子中,我在每个节点上使用 TextBoxes 进行了 TwoWay 绑定,但是当涉及到在单独的单个 TextBox 或其他控件,您会将其绑定到 TreeView 的当前选定项.您还可以将上面的 TextBoxes 更改为 TextBlocks,因为单击 TextBox 实际上并没有选择相应的 TreeViewItem.

I this example, I did TwoWay binding with TextBoxes on each node, but when it comes to editing just one node at a time in a separate, single TextBox or other control, you would be binding it to the currently selected item of the TreeView. You would also change the above TextBoxes to TextBlocks, as clicking in the TextBox does not actually select the corresponding TreeViewItem.

<TextBox
    DataContext="{Binding ElementName=treeview, Path=SelectedItem}"
    Text="{Binding XPath=data, UpdateSourceTrigger=PropertyChanged}"/>

你必须使用两个Binding的原因是你不能同时使用PathXPath.

The reason you must use two Bindings is that you cannot use Path and XPath together.

Timothy Lee Russell 询问了将 CDATA 保存到数据元素的问题.首先,稍微介绍一下 InnerXmlInnerText.

Timothy Lee Russell asked about saving CDATA to the data elements. First, a little on InnerXml and InnerText.

在幕后,XmlDataProvider 使用了一个 XmlDocument,它是 XmlNodes 的树.如果将诸如stuff"之类的字符串分配给 XmlNodeInnerXml 属性,那么这些标签就是真正的标签.获取或设置InnerXml时不进行转义,解析为XML.

Behind the scenes, XmlDataProvider is using an XmlDocument, with it's tree of XmlNodes. When a string such as "stuff" is assigned to the InnerXml property of an XmlNode, then those tags are really tags. No escaping is done when getting or setting InnerXml, and it is parsed as XML.

然而,如果它被分配给 InnerText 属性,尖括号将被转义为实体 &lt;和 &gt;.取回值时,情况正好相反.实体(如 &lt;)被解析回字符(如 <).

However, if it is instead assigned to the InnerText property, the angle brackets will be escaped with entities &lt; and &gt;. The reverse happens when the value is retreived. Entities (like &lt;) are resolved back into characters (like <).

因此,如果我们存储在数据元素中的字符串包含 XML,实体已被转义,我们需要通过在添加 CDATA 部分作为节点的子节点之前检索 InnerText 来撤消该操作..

Therefore, if the strings we store in the data elements contain XML, entities have been escaped, and we need to undo that simply by retrieving InnerText before adding a CDATA section as the node's child...

XmlDocument doc = dp.Document;

XmlNodeList nodes = doc.SelectNodes( "//data" );

foreach ( XmlNode node in nodes ) {
    string data = node.InnerText;
    node.InnerText = "";
    XmlCDataSection cdata = doc.CreateCDataSection( data );
    node.AppendChild( cdata );
}

doc.Save( dp.Source.LocalPath );

如果节点已经有一个 CDATA 部分并且值没有以任何方式改变,那么它仍然有一个 CDATA 部分,我们基本上用相同的部分替换它.但是,通过我们的绑定,如果我们更改数据元素内容的值,它会替换 CDATA 以支持转义字符串.然后我们必须修复它们.

If the node already has a CDATA section and the value has not been changed in any way, then it still has a CDATA section and we essentially replace it with the same. However, through our binding, if we change the value of the data elements contents, it replaces the CDATA in favor of an escaped string. Then we have to fix them.

这篇关于Xml 数据到 WPF TreeView 的双向绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆