如何选择数据绑定TreeViewItem?

时间:2011-03-23 15:29:33

标签: wpf xml treeview data-binding xmldataprovider

我有一个带有XmlDataProvider的TreeView的XML数据绑定。如果我向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 个答案:

答案 0 :(得分:1)

blog post介绍了如何选择项目。基本上,您不能只使用TreeView.ItemContainerGenerator,因为它只允许您访问根TreeViewItems。使用父TreeViewItem的TreeViewItem.ItemContainerGenerator访问嵌套的TreeViewItem。

答案 1 :(得分:0)

我有第一种方法:

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

如果我将他添加到位置1的类别,则选择newNode,否则我成为例外; - )

现在我处理一个具有多个级别的动态: - )

答案 2 :(得分:0)

已经很晚了,所以我的功能不是最顺畅的,但它确实有效! 我曾经对所有曾经有同样问题的人发表评论; - )

Usings:

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