【问题标题】:How to select a databound TreeViewItem?如何选择数据绑定的 TreeViewItem?
【发布时间】:2011-03-23 15:29:32
【问题描述】:

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

【问题讨论】:

    标签: wpf xml treeview data-binding xmldataprovider


    【解决方案1】:

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

    【讨论】:

    • 我知道我不能使用 ItemContainerGenerator 并且它只允许我访问根项目。我发现它很困难:-D 你的博客帖子很有趣,我明天试试 ;-)
    • 我已经测试了这个例子,但它没有工作,因为正如你所说,它只是让我可以访问根 TreeViewItems。所以我想我需要一个递归......但是如何?第一次调用 treeView.ItemContainerGenerator.ContainerFromIndex(..) 我变成了 TreeViewItem 而不是另一个容器,我有点卡住了:-(
    • 谢谢,但现在我已经完成了艰难的工作,只是比你的解决方案长一点;-)
    【解决方案2】:

    我有第一种方法:

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

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

    现在我在不止一个级别的动态上工作:-)

    【讨论】:

      【解决方案3】:

      已经很晚了,所以我的功能不是最流畅的,但它可以工作! 我已经评论过所有曾经有同样问题的人;-)

      用途:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-05
        • 2015-01-18
        • 2010-09-18
        • 2012-04-23
        • 2013-08-04
        相关资源
        最近更新 更多