Как выбрать привязанный к дереву TreeViewItem? - PullRequest
0 голосов
/ 23 марта 2011

У меня есть привязка данных XML к TreeView с XmlDataProvider.Если я добавлю подузел в XML, TreeView покажет его, но как мне выбрать этот элемент?

XAML:

<Window.Resources>
    <HierarchicalDataTemplate DataType="category" ItemsSource="{Binding XPath=child::node()}">
        <TextBlock Text="{Binding XPath=@name}" 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>

Ответы [ 3 ]

1 голос
/ 24 марта 2011

Это сообщение в блоге описывает, как выбрать элемент.По сути, вы не можете просто использовать TreeView.ItemContainerGenerator, так как это просто дает вам доступ к корневому TreeViewItems.Доступ к вложенным элементам TreeViewItems осуществляется с помощью TreeViewItem.ItemContainerGenerator родительского TreeViewItem.

0 голосов
/ 25 марта 2011

Уже поздно, поэтому мои функции не самые плавные, но это работает!Я прокомментировал это для всех, кто когда-то имел ту же проблему; -)

Использование:

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

Функция:

/// <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;
    }
}
0 голосов
/ 25 марта 2011

У меня первый подход:

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

выбирает новый узел, если я добавляю его в категорию на позиции 1, в противном случае я становлюсь исключением; -)

Теперь я работаю над динамикой один раз с более чем одним уровнем: -)

...