Estoy tratando de escribir mi ForestPad aplicación utilizando WPF para la capa de presentación. En WinForms, estoy rellenando cada uno de los nodos mediante programación, pero me gustaría tomar ventaja de las capacidades de enlace de datos de WPF, si es posible.

En general, ¿cuál es la mejor forma de dos vías databind WPF vista de un documento Xml?

Una solución genérica está bien, pero a modo de referencia, la estructura del documento Xml que estoy tratando de enlazar a este aspecto:

<?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>

2 Comentarios

  1. 7

    Bien, sería más fácil si el elemento de la jerarquía era más como…

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

    …en lugar de su esquema actual.

    Tal como es, usted necesitará 4 HierarchicalDataTemplates, uno para cada elemento jerárquico, incluyendo la raíz, y una DataTemplate para leaf elementos:

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

    Usted puede en lugar de establecer el Source de la XmlDataProvider programación:

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

    También, volver a guardar sus ediciones es tan fácil como esto:

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

    La TreeView necesita una Name y un ItemsSource adheridos a la XmlDataProvider:

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

    I en este ejemplo, hice TwoWay de unión con TextBoxes en cada nodo, pero cuando se trata de edición de un nodo en un tiempo en un aparte, solo TextBox o el control de otro, que sería vinculante para el elemento seleccionado de la TreeView. También se cambio el de arriba TextBoxes a TextBlocks, como hacer clic en el TextBox en realidad no seleccionar la correspondiente TreeViewItem.

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

    La razón se debe utilizar dos Bindings es que no se puede utilizar Path y XPath juntos.

    Edición:

    Timothy Lee Russell le preguntó sobre el ahorro CDATA a los elementos de datos. En primer lugar, un poco en InnerXml y InnerText.

    Detrás de las escenas, XmlDataProvider es el uso de un XmlDocument, con el árbol de la XmlNodes. Cuando una cadena como «cosas» es asignado a la InnerXml propiedad de un XmlNode, entonces esas etiquetas son realmente las etiquetas. Hay escape se lleva a cabo cuando obtener o establecer InnerXml, y se analiza como XML.

    Sin embargo, si es el lugar asignado a la InnerText de la propiedad, el ángulo de los soportes se escapó con entidades &lt; y &gt;. A la inversa ocurre cuando el valor es recuperada. Entidades (como &lt;) se resuelve de nuevo en los personajes (como <).

    Por lo tanto, si las cadenas se almacena en los elementos de datos que contienen XML, las entidades se han escapado, y tenemos que deshacer de que simplemente por la recuperación de InnerText antes de la adición de una sección CDATA como el nodo del niño…

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

    Si el nodo ya tiene una sección CDATA, y el valor no ha sido cambiado en cualquier forma, todavía tiene una sección CDATA, y que esencialmente reemplazar con la misma. Sin embargo, a través de nuestro enlace, si cambiamos el valor de los elementos de datos de contenido, que sustituye a la CDATA en favor de un escapó de la cadena. Entonces nos tenemos que fijar en ellos.

    • Gracias Joel, que funciona. Una pregunta, sin embargo. Me rodean los contenidos en el elemento de datos con una sección CDATA, de modo que es posible almacenar Xml. Es allí una manera de controlar la forma en la XmlDataProvider escribe el elemento de datos?
    • Si no es XML como una cadena, se escapaba de los corchetes angulares con las entidades (que comienzan con &). Esto puede ser revertido debido a que el Documento de propiedad devuelve un XmlDocument. Voy a editar y agregar el código para hacer CDATA en los elementos de datos.
    • – Esa funciona. El rendimiento es muy malo para el tamaño de los documentos que estoy trabajando con el, pero en lugar de actualizar cada nodo, voy a añadir un IsDirty bandera y sólo la actualización de los nodos que han sido editados.
    • Yo también no quiero un nodo raíz, así que he cambiado el XPath en el ItemsSource de la vista de «XPath=bosque» en lugar de «XPath=.», que funciona a la perfección.
    • Muchas gracias por tu ayuda!
    • Me doy cuenta de que este es un viejo Q&A, pero esta respuesta me ha ayudado mucho hoy en día, así que quería darte las gracias. Soy curioso, sin embargo, ¿cómo sería la solución son diferentes si el XML fueron los node árbol, como usted sugiere?
    • La normalización. Cada elemento tiene los mismos atributos, por lo que bien podría ser el mismo tipo de datos. A continuación, usted no está limitado a una determinada profundidad por su estructura de datos, o no tener que lidiar con las hojas y las ramas en ramas. Usted simplemente tiene nodos dentro de los nodos. Ahora, puede haber razones para que el diseño, pero esto no significa tener varios HierarchicalDataTemplates en lugar de uno.
    • La justificación (para mejor o peor) se describe en el artículo tras el salto. Como con una gran cantidad de decisiones, fue algo arbitrario. En la versión web de ForestPad que estoy construyendo actualmente con ASP.NET WebAPI y AngularJS, estoy utilizando el mismo tipo de datos para cada nodo con profundidad ilimitada. Enlace a la edad ForestPad artículo: codeproject.com/Articles/7255/…

Dejar respuesta

Please enter your comment!
Please enter your name here