4

プレゼンテーション層にWPFを使用してForestPadアプリケーションを書き直そうとしています。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>
4

3 に答える 3

8

ええと、あなたの要素階層がもっと似ていればもっと簡単でしょう...

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

...現在のスキーマではなく。

HierarchicalDataTemplate現状では、ルートを含む各階層要素に1つDataTemplateleaf要素に1つ、合計4つのが必要です。

<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あり、:にItemsSource結合されていXmlDataProviderます

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

この例では、各ノードでesを使用してTwoWayバインドしましたが、個別の単一またはその他のコントロールで一度に1つのノードのみを編集する場合は、現在選択されているの項目にバインドすることになります。をクリックしても実際には対応するが選択されないため、上記のesをsに変更することもできます。TextBoxTextBoxTreeViewTextBoxTextBlockTextBoxTreeViewItem

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

2つのを使用する必要がある理由は、一緒にBinding使用することはできないためです。PathXPath

編集:

Timothy Lee Russellは、CDATAをデータ要素に保存することについて質問しました。まず、少し上InnerXmlInnerText

舞台裏では、のツリーで、をXmlDataProvider使用しています。「stuff」などの文字列がのプロパティに割り当てられている場合、それらのタグは実際にはタグです。取得または設定時にエスケープは行われず、XMLとして解析されます。XmlDocumentXmlNodesInnerXmlXmlNodeInnerXml

ただし、代わりにInnerTextプロパティに割り当てられている場合、山括弧はエンティティ&lt;でエスケープされます。および&gt;。値が取得されると、逆のことが起こります。エンティティ(&lt;など)は、文字(<など)に分解されます。

したがって、データ要素に格納する文字列にXMLが含まれている場合、エンティティはエスケープされてInnerTextおり、ノードの子として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セクションがあり、値がまったく変更されていない場合でも、ノードにはCDATAセクションがあり、基本的に同じものに置き換えます。ただし、バインディングを介して、データ要素の内容の値を変更すると、エスケープされた文字列が優先されてCDATAが置き換えられます。次に、それらを修正する必要があります。

于 2008-10-09T16:33:40.270 に答える
2

同様の問題がありました。この記事を読むと役立つ場合があります。説明したViewModelパターンを使用して、すべてを単純化しました。

于 2008-10-09T16:36:52.743 に答える