问题描述
我正在尝试使用 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 HierarchicalDataTemplate
s, 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>
您可以改为以编程方式设置 XmlDataProvider
的 Source
:
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=.}">
在这个例子中,我在每个节点上使用 TextBox
es 进行了 TwoWay
绑定,但是当涉及到在单独的单个 TextBox
或其他控件,您会将其绑定到 TreeView
的当前选定项.您还可以将上面的 TextBox
es 更改为 TextBlock
s,因为单击 TextBox
实际上并没有选择相应的 TreeViewItem.
I this example, I did
TwoWay
binding with TextBox
es 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 TextBox
es to TextBlock
s, 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
的原因是你不能同时使用Path
和XPath
.
The reason you must use two
Binding
s 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
属性,尖括号将被转义为实体 <和 >.取回值时,情况正好相反.实体(如 <)被解析回字符(如 <).
However, if it is instead assigned to the
InnerText
property, the angle brackets will be escaped with entities < and >. The reverse happens when the value is retreived. Entities (like <) 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 的双向绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!