代码之家  ›  专栏  ›  技术社区  ›  Timothy Lee Russell

Xml数据到WPF TreeView的双向绑定

  •  4
  • Timothy Lee Russell  · 技术社区  · 17 年前

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

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

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

    <?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>
    
    3 回复  |  直到 14 年前
        1
  •  8
  •   Joel B Fant    17 年前

    好吧,如果你的元素层次结构更像这样,那就更容易了。..

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

    …而不是您当前的模式。

    目前,你需要4个 HierarchicalDataTemplate s、 一个用于包括根的每个层次元素,另一个用于 DataTemplate leaf 元素:

    <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 以编程方式:

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

    此外,重新保存您的编辑很容易:

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

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

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

    我举了这个例子 TwoWay 绑定与 TextBox es位于每个节点上,但在单独的单个节点中一次只编辑一个节点时 文本框 或其他控件,您将把它绑定到当前选定的项 树视图 。您也可以更改上述内容 文本框 es to TextBlock s、 点击 文本框 实际上没有选择相应的 TreeViewItem .

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

    你必须使用两个的原因 Binding s是你不能用 Path XPath 一起。

    编辑:

    Timothy Lee Russell询问如何将CDATA保存到数据元素中。首先,稍微说一点 InnerXml InnerText .

    在幕后, XmlDataProvider 正在使用 XmlDocument ,与它的树 XmlNodes .当一个字符串(如“stuff”)被分配给 内部Xml a的财产 XmlNode ,那么这些标签就是真正的标签。到达或设置时不会逃跑 内部Xml ,并将其解析为XML。

    但是,如果将其分配给 标记模板 属性,尖括号将与实体一起转义;lt;和&gt;。当检索值时,情况正好相反。实体(如&lt;)被解析回字符(如<)。

    因此,如果我们存储在数据元素中的字符串包含XML,则实体已被转义,我们只需检索 标记模板 在将CDATA部分添加为节点的子节点之前。..

    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部分,并且值没有以任何方式更改,那么它仍然有一个CD ATA部分,我们基本上用相同的部分替换它。然而,通过我们的绑定,如果我们更改了数据元素内容的值,它将替换CDATA,转而使用转义字符串。然后我们必须修复它们。

        2
  •  2
  •   Shaun Bowe    17 年前

    我们也遇到了类似的问题。你可能会发现阅读 this article 有帮助。我们使用了所描述的ViewModel模式,它简化了一切。