双向XML数据的结合WPF的树视图 [英] Two-way binding of Xml data to the WPF TreeView

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

问题描述

我试图重写我的 ForestPad 利用WPF为presentation层应用程序。在的WinForms,我填充编程的每个节点,但我想利用WPF的的数据绑定功能的优势,如果可能的话。

在一般的,什么是双向数据绑定的WPF的TreeView的最佳方式对XML文档?

一个通用的解决方案是好的,但参考,我试图绑定到看起来像这样的XML文档的结构:

 <?XML版本=1.0编码=UTF-8&GT?;
< forestPad
    GUID =6c9325de-dfbe-4878-9d91-1a9f1a7696b0
    创建=2004年5月14日上午01点05分10秒
    更新=2004年5月14日上午01时07分41秒>
<森林
    NAME =A林节点
    GUID =b441a196-7468-47c8-a010-7ff83429a37b
    创建=01/01/2003 1:00:00 AM。
    更新=2004年5月14日上午01时06分15秒>
    <数据>
    <![CDATA [A林节点
        这是林节点的文本]>
    < /数据>
    <树
        NAME =树节点
        GUID =768eae66-e9df-4999-b950-01fa9be1a5cf
        创建=2004年5月14日上午01时05分38秒
        更新=2004年5月14日上午01时06分11秒>
        <数据>
        <![CDATA [树节点
            这是树节点的文本]>
        < /数据>
        <分支
            NAME =分支节点
            GUID =be4b0993-d4e4-4249-8aa5-fa9c940ae2be
            创建=2004年5月14日上午01时06分00秒
            更新=2004年5月14日上午01时06分24秒>
            <数据>
            <![CDATA [分支节点
                这是分支节点的文本]方式>&下; /数据>
                <叶
                NAME =叶节点
                GUID =9c76ff4e-3ae2-450e-b1d2-232b687214aa
                创建=2004年5月14日上午01时06分26秒
                更新=2004年5月14日上午01时06分38秒>
                <数据>
                <![CDATA [叶节点
                    这是叶节点的文本]>
                < /数据>
            < /叶>
        < /支>
    < /树>
< /森林>
< / forestPad>


解决方案

那么,它会更容易,如果你的元素层次更像...

 <节点类型=森林>
    <节点类型=树>
        ...

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

由于-是,你需要4 HierarchicalDataTemplate S,一个是包括根各层次的元素,一个的DataTemplate 元素:

 < Window.Resources>
    < HierarchicalDataTemplate
        数据类型=forestPad
        的ItemsSource ={结合的XPath =森林}>
        <的TextBlock
            文本=一个forestpad/>
    < / HierarchicalDataTemplate>
    < HierarchicalDataTemplate
        数据类型=森林
        的ItemsSource ={结合的XPath =树}>
        <文本框
            文本={结合的XPath =数据}/>
    < / HierarchicalDataTemplate>
    < HierarchicalDataTemplate
        数据类型=树
        的ItemsSource ={结合的XPath =分支}>
        <文本框
            文本={结合的XPath =数据}/>
    < / HierarchicalDataTemplate>
    < HierarchicalDataTemplate
        数据类型=分支
        的ItemsSource ={结合的XPath =叶}>
        <文本框
            文本={结合的XPath =数据}/>
    < / HierarchicalDataTemplate>
    <的DataTemplate
        数据类型=叶子>
        <文本框
            文本={结合的XPath =数据}/>
    < / DataTemplate中>    < XmlDataProvider
        X:键=dataxml
        XPath的=forestPad来源=D:\\ fp.xml>
    < / XmlDataProvider>
< /Window.Resources>

您可以代替设置的来源 XmlDataProvider 编程方式:

  DP = this.FindResource(dataxml)作为XmlDataProvider;
dp.Source =新的URI(@D:\\ fp.xml);

此外,重新保存编辑是那么容易,因为这样的:

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

TreeView控件本身需要名称的ItemsSource 键合到 XmlDataProvider

 < TreeView控件
    NAME =树视图
    的ItemsSource ={绑定源= {StaticResource的dataxml},XPath的=。}>

我这个例子,我做了双向文本框结合的每个节点,但在上课时谈到编辑只是一次在一个单独的,单一的文本框节点或其它控制,你会被它绑定到 TreeView控件的当前选择的项目。您也将改变上述文本框下载到的TextBlock S,如单击文本框不实际选择相应的树型视图

 <文本框
    的DataContext ={绑定的ElementName =树视图,路径=的SelectedItem}
    文本={结合的XPath =数据,UpdateSourceTrigger =的PropertyChanged}/>

究其原因,你必须使用两个绑定 s的,你不能使用路径 XPath的在一起。

编辑:

李提摩太罗素问有关保存CDATA的数据元素。首先,在一个小 InnerXml 的InnerText

在幕后, XmlDataProvider 是使用的XmlDocument ,与它的树将XMLNode 。当一个字符串,如东西被分配到一个的XmlNode ,那么这些标记是真正标记的 InnerXml 属性。无法回避完成获取或设置当 InnerXml ,它解析为XML。

然而,如果不是分配给的InnerText 属性,尖括号将与实体&放逃脱; LT;和&安培;取代。当值retreived情况相反。实体(如&放大器; LT)被解析回字符(比如≤)。

因此​​,如果我们在数据元素存储字符串包含XML,实体已经逃跑,我们需要撤消,仅仅通过检索的InnerText 添加CDATA节之前作为节点的孩子......

  XmlDocument的DOC = dp.Document;XmlNodeList中的节点= doc.SelectNodes(//数据);的foreach(在节点XmlNode的节点){
    字符串数据= node.InnerText;
    node.InnerText =;
    XmlCDataSection CDATA = doc.CreateCDataSection(数据);
    node.AppendChild(CDATA);
}doc.Save(dp.Source.LocalPath);

如果该节点已经有一个CDATA部分和价值没有以任何方式被改变,那么它仍然有一个CDATA部分,我们基本上是用相​​同的替换它。但是,通过我们的结合,如果我们改变数据元素含量的价值,它取代赞成转义字符串的CDATA。然后,我们必须解决这些问题。

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.

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

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.

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>

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

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

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

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

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

Edit:

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

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.

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

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

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的树视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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