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

查看:983
本文介绍了将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 for 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>

您可以将 Source xmlDataProvider 以编程方式:

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 本身需要一个名称 ItemsSource 绑定到 XmlDataProvider

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

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

我这个例子,我做了 TwoWay binding在每个节点上使用 TextBox es,但是当一个单独的 TextBox 或其他控件,您将绑定到 TreeView 当前选定的项目。您也可以将 TextBox es更改为 TextBlock ,点击 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}"/>

你必须使用两个绑定的原因绑定是不能一起使用路径 XPath

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

编辑:

Timothy Lee Russell询问将CDATA保存到数据元素。首先,在 InnerXml InnerText

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

使用 XmlDataProvider 正在使用 XmlDocument ,其树为 XmlNodes 。当一个诸如stuff的字符串被分配给 XmlNode InnerXml 属性时,那些标签是真正的标签。获取或设置 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,被转义,我们需要通过检索 InnerText ,然后再将CDATA部分添加到节点的子节点中。

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天全站免登陆