2011-03-23 3 views
0

J'ai une base de données XML vers un TreeView avec un XmlDataProvider. Si j'ajoute un sous-noeud au XML, TreeView le montre, mais comment puis-je sélectionner cet élément?Comment sélectionner une TreeViewItem de databound?

XAML:

<Window.Resources> 
    <HierarchicalDataTemplate DataType="category" ItemsSource="{Binding XPath=child::node()}"> 
     <TextBlock Text="{Binding [email protected]}" FontWeight="Bold" /> 
    </HierarchicalDataTemplate> 

    <HierarchicalDataTemplate DataType="card"> 
     <TextBlock Text="{Binding XPath=./title}" FontStyle="Italic" /> 
    </HierarchicalDataTemplate> 

    <XmlDataProvider x:Key="dataxml" XPath="root/cards"/> 

</Window.Resources> 

<TreeView Name="treeView" 
      ItemsSource="{Binding Source={StaticResource dataxml}, 
          XPath=./*, 
          UpdateSourceTrigger=PropertyChanged}" 
/> 

CS:

public partial class MainWindow : Window 
{ 
    XmlDataProvider xmlDataProvider = new XmlDataProvider(); 

    public MainWindow() 
    { 
     InitializeComponent();   
     xmlDataProvider = this.FindResource("dataxml") as XmlDataProvider; 
     xmlDataProvider.Source = new Uri(System.IO.Path.GetFullPath(fullPathToXml), UriKind.Absolute); 
     xmlDataProvider.Refresh(); 
    } 

    public void AddChild() 
    { 
     XmlNode newNode = xmlDataProvider.Document.CreateElement("card"); 
     XmlNode selectedItem = (XmlNode)treeView.SelectedItem; 

     if (selectedItem != null) 
     { 
      //add the newNode as child to the selected 
      selectedItem.AppendChild(newNode); 
      //select the childnode (newNode) ?????  <===== 
     } 
     else 
     { 
      //add the newNode as child to the rootnode and select it: 
      xmlDataProvider.Document.DocumentElement["cards"].AppendChild(newNode); 
      (treeView.ItemContainerGenerator.ContainerFromItem(newNode) as TreeViewItem).IsSelected = true; 
     } 

     xmlDataProvider.Document.Save(fullPathToXml); 
     xmlDataProvider.Refresh(); 
    } 
} 

XML:

<root> 
    <settings> 
    .... 
    .. 
    </settings> 
    <cards> 
    <category name="C1"> 
     <card name="card1"> 
      <question>bla</question> 
      <answer>blub</answer> 
     </card> 
     <category name="C2"> 
      <card name="card4"> 
       <question>bla</question> 
       <answer>blub</answer> 
      </card> 
     </category> 
    </category> 
     <card name="card2"> 
      <question>bla</question> 
      <answer>blub</answer> 
     </card> 
     <card name="card3"> 
      <question>bla</question> 
      <answer>blub</answer> 
     </card> 
    </cards> 
</root> 

Répondre

0

Il est tard, donc mes fonctions ne sont pas les plus fluides, mais ça marche! J'ai des commentaires pour tous ceux qui ont une fois le même problème ;-)

usings:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Controls; 
using System.Xml; 
using System.Runtime.InteropServices; 

Fonction:

/// <summary> 
/// Select a XmlNode in a TreeView that is databound to a xmlDataProvider. 
/// </summary> 
/// <param name="treeView">A referenz to the TreeView.</param> 
/// <param name="node">The node to select.</param> 
public static void SelectTreeViewNode(ref TreeView treeView, XmlNode node) 
{ 
    if (treeView.HasItems) 
    { 
     //cast to xml-nodes 
     var xmlNodeList = treeView.Items.Cast<XmlNode>(); ; 

     //node at root level? -> select it 
     if (xmlNodeList.Contains(node)) 
     { 
      (treeView.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem).IsSelected = true; 
     } 
     else 
     { 
      //get rootnode 
      XmlNode rootNode = GetRootNode(node, xmlNodeList); 

      //get a list of parent nodes 
      List<XmlNode> parentNodes = new List<XmlNode>(); 
      GetAllParentNodes(rootNode, node, ref parentNodes); 
      parentNodes.Reverse(); 

      //finaly, select the node 
      SelectNode(parentNodes, node, ref treeView, null); 
     } 

    } 
} 

/// <summary> 
/// Goes recursiv down the parent nodes until he finds a node that is in the xmlNodeList. 
/// Returns null if he can´t find anything. 
/// </summary> 
/// <param name="node">The start node.</param> 
/// <param name="xmlNodeList">A list with possible rootnodes.</param> 
/// <returns>The rootnode</returns> 
private static XmlNode GetRootNode(XmlNode node, IEnumerable<XmlNode> xmlNodeList) 
{ 
    if (!xmlNodeList.Contains(node) && node.ParentNode != null) 
    { 
     return GetRootNode(node.ParentNode, xmlNodeList); 
    } 
    else if (xmlNodeList.Contains(node)) return node; 
    else return null; 
} 

/// <summary> 
/// Returns all parent nodes from the actual node within the rootNode. Works recursiv. 
/// </summary> 
/// <param name="rootNode">The rootnode.</param> 
/// <param name="actualNode">The startnode</param> 
/// <param name="parentNodes">The rererenz to the outputlist</param> 
private static void GetAllParentNodes(XmlNode rootNode, XmlNode actualNode, ref List<XmlNode> parentNodes) 
{ 
    if (actualNode.ParentNode != null && !actualNode.Equals(rootNode)) 
    { 
     parentNodes.Add(actualNode.ParentNode); 
     GetAllParentNodes(rootNode, actualNode.ParentNode, ref parentNodes); 
    } 
} 

/// <summary> 
/// Select a XmlNode from a TreeView that is databound to a xmlDataProvider. 
/// </summary> 
/// <param name="parentNodes">All the parent nodes, first in the list is the rootnode.</param> 
/// <param name="node">The node to select.</param> 
/// <param name="treeView">A referenz to the TreeView.</param> 
/// <param name="item">Variable for the recursion.</param> 
private static void SelectNode(List<XmlNode> parentNodes, XmlNode node, ref TreeView treeView, [Optional, DefaultParameterValue(null)] TreeViewItem item) 
{ 
    if (parentNodes.Count > 0) 
    { 
     TreeViewItem tvItem; 
     if (item != null) 
      tvItem = item.ItemContainerGenerator.ContainerFromItem(parentNodes.First()) as TreeViewItem; 
     else 
      tvItem = treeView.ItemContainerGenerator.ContainerFromItem(parentNodes.First()) as TreeViewItem; 
     parentNodes.RemoveAt(0); 
     SelectNode(parentNodes, node, ref treeView, tvItem); 
    } 
    else if (item != null) 
    { 
     (item.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem).IsSelected = true; 
    } 
} 
1

Cette blog post décrit comment sélectionner un élément. Fondamentalement, vous ne pouvez pas simplement utiliser TreeView.ItemContainerGenerator, car cela vous donne juste accès à la racine TreeViewItems. Les TreeViewItems imbriqués sont accessibles à l'aide de TreeViewItem.ItemContainerGenerator du TreeViewItem parent.

+0

je sais que je ne peux pas utiliser la ItemContainerGenerator et qu'il me donne seulement l'accès aux éléments racine. Je l'ai trouvé à la dure :-D Votre article de blog est interessant, je vais l'essayer demain ;-) – jwillmer

+0

J'ai testé l'exemple et ça n'a pas fonctionné car comme vous l'aviez dit il me donne juste accès à la racine TreeViewItems. Donc je pense que j'ai besoin d'une récursivité ... mais comment? avec le premier appel de treeView.ItemContainerGenerator.ContainerFromIndex (..) je suis devenu TreeViewItem et pas un autre conteneur, je suis un peu coincé :-( – jwillmer

+0

thx, mais maintenant je l'ai fait à la dure, juste un peu plus longtemps que votre Solution ;-) – jwillmer

0

J'ai une première approche:

((treeView.ItemContainerGenerator.ContainerFromIndex(1) as TreeViewItem).ItemContainerGenerator.ContainerFromItem(newNode) as TreeViewItem).IsSelected = true; 

Sélectionne le newNode si je l'ajouter à la catégorie sur la position 1, sinon je deviens une exception ;-)

maintenant je travaille sur une dynamique une fois avec plus d'un niveau :-)

Questions connexes