How to select a databound TreeViewItem?

2020-05-06 14:13发布

I have a XML databound to a TreeView with a XmlDataProvider. If i add a subnode to the XML the TreeView shows it, but how can i select this item?

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条回答
再贱就再见
2楼-- · 2020-05-06 14:41

I have a first approach:

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

this selects the newNode if i add him to the category on position 1, otherwise i become an exception ;-)

now i work on a dynamic once with more than one level :-)

查看更多
We Are One
3楼-- · 2020-05-06 14:43

It is late, so my functions arent the smoothest, but it works! I have comment it for all that once have the same problem ;-)

Usings:

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

Function:

/// <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;
    }
}
查看更多
趁早两清
4楼-- · 2020-05-06 14:49

This blog post describes how to select an item. Basically, you can't just use the TreeView.ItemContainerGenerator, as that just gives you access to the root TreeViewItems. The nested TreeViewItems are accessed using the TreeViewItem.ItemContainerGenerator of the parent TreeViewItem.

查看更多
登录 后发表回答