问题描述:

http://stackoverflow.com/questions/616948/how-to-get-treeviewitem-from-hierarchicaldatatemplate-item

找到比较靠谱的答案:

http://blogs.msdn.com/b/wpfsdk/archive/2010/02/23/finding-an-object-treeviewitem.aspx

The question often comes up, "how do I get to a certain TreeViewItem?" The question arises because a TreeView is bound to a data source, TreeViewItems are implicitly created and wrap the data object. However, the TreeView.SelectedItem property returns the data object, not the TreeViewItem. This is good when you need to access the data, but what if you need to manipulate the TreeViewItem? It has been suggested that if you design your data model correctly, you can avoid needing to manipulate TreeViewItems directly. While that is good general advice, there might be cases where manipulating the TreeViewItem is unavoidable.

Finding the TreeViewItem in a TreeView is more involved than finding item containers in other ItemControls (such as a ListBoxItem in a ListBox) because TreeViewItems are, naturally, nested. For example, to return the ListBoxItem of an object in a ListBox, you can callListBox.ItemContainerGenerator.GetContainerFromItem. But if you call GetContainerFromItem on a TreeView, the ItemContainerGenerator searches only the direct child objects of the TreeView. So you need to recursively traverse the TreeView and child TreeViewItem objects. A further complication is that if the TreeView virtualizes its items (you enable virtualization by setting theVirtualizingStackPanel.IsVirtualizing property to true), the child items need to be created before you can check its data object.

Given the complexity of the problem, I (with help from the development team) created a method that traverses the TreeView and realizes any virtualized items.

/// <summary>

/// Recursively search for an item in this subtree.

/// </summary>

/// <param name="container">

/// The parent ItemsControl. This can be a TreeView or a TreeViewItem.

/// </param>

/// <param name="item">

/// The item to search for.

/// </param>

/// <returns>

/// The TreeViewItem that contains the specified item.

/// </returns>

private TreeViewItem GetTreeViewItem(ItemsControl container, object item)

{

if (container != null)

{

if (container.DataContext == item)

{

return container as TreeViewItem;

}

// Expand the current container

if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)

{

container.SetValue(TreeViewItem.IsExpandedProperty, true);

}

// Try to generate the ItemsPresenter and the ItemsPanel.

// by calling ApplyTemplate. Note that in the

// virtualizing case even if the item is marked

// expanded we still need to do this step in order to

// regenerate the visuals because they may have been virtualized away.

container.ApplyTemplate();

ItemsPresenter itemsPresenter =

(ItemsPresenter)container.Template.FindName("ItemsHost", container);

if (itemsPresenter != null)

{

itemsPresenter.ApplyTemplate();

}

else

{

// The Tree template has not named the ItemsPresenter,

// so walk the descendents and find the child.

itemsPresenter = FindVisualChild<ItemsPresenter>(container);

if (itemsPresenter == null)

{

container.UpdateLayout();

itemsPresenter = FindVisualChild<ItemsPresenter>(container);

}

}

Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);

// Ensure that the generator for this panel has been created.

UIElementCollection children = itemsHostPanel.Children;

MyVirtualizingStackPanel virtualizingPanel =

itemsHostPanel as MyVirtualizingStackPanel;

for (int i = 0, count = container.Items.Count; i < count; i++)

{

TreeViewItem subContainer;

if (virtualizingPanel != null)

{

// Bring the item into view so

// that the container will be generated.

virtualizingPanel.BringIntoView(i);

subContainer =

(TreeViewItem)container.ItemContainerGenerator.

ContainerFromIndex(i);

}

else

{

subContainer =

(TreeViewItem)container.ItemContainerGenerator.

ContainerFromIndex(i);

// Bring the item into view to maintain the

// same behavior as with a virtualizing panel.

subContainer.BringIntoView();

}

if (subContainer != null)

{

// Search the next level for the object.

TreeViewItem resultContainer = GetTreeViewItem(subContainer, item);

if (resultContainer != null)

{

return resultContainer;

}

else

{

// The object is not under this TreeViewItem

// so collapse it.

subContainer.IsExpanded = false;

}

}

}

}

return null;

}

/// <summary>

/// Search for an element of a certain type in the visual tree.

/// </summary>

/// <typeparam name="T">The type of element to find.</typeparam>

/// <param name="visual">The parent element.</param>

/// <returns></returns>

private T FindVisualChild<T>(Visual visual) where T : Visual

{

for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)

{

Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);

if (child != null)

{

T correctlyTyped = child as T;

if (correctlyTyped != null)

{

return correctlyTyped;

}

T descendent = FindVisualChild<T>(child);

if (descendent != null)

{

return descendent;

}

}

}

return null;

}

Note that this code looks for a Panel called, MyVirtualizingStackPanel. This new type exposes a method that allows you to bring an item into view by passing in the item's index.

public class MyVirtualizingStackPanel : VirtualizingStackPanel

{

/// <summary>

/// Publically expose BringIndexIntoView.

/// </summary>

public void BringIntoView(int index)

{

this.BringIndexIntoView(index);

}

}

The final step is to use the custom VirtualizingStackPanel as the TreeView's ItemsPanel:

<TreeView VirtualizingStackPanel.IsVirtualizing="True">
<!--Use the custom class MyVirtualizingStackPanel
as the ItemsPanel for the TreeView and
TreeViewItem object.-->
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<src:MyVirtualizingStackPanel/>
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<src:MyVirtualizingStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>

Now that you have the code, you can search for any object in any TreeView, regardless of its depth in the tree.

I attached a sample that uses this technique to find any item in the TreeView. The sample asks for a number, finds the corresponding data object in the data model, and then selects the TreeViewItem that contains the object. Note that the way I find the data object in the model is specific to the organization of my data. I could have kept track of the data object's location within the data hierarchy, and then find the corresponding TreeViewItem in the TreeView.

For example, the item that corresponds to 41 is, starting from the root of the TreeView, under the second item, then under the first item, then under the second item, and finally the first item. I could have kept track of its location with a list of indices, 2,1,2,1, and then used those to navigate the TreeView. However, this approach is dependent on the organization of the underlying TreeView. The implementation I show above works on any TreeView and it doesn't require knowledge of the data model.

The attached sample has C# and Visual Basic versions.

源代码

Silverligh中目前仍有问题:

TreeViewItem中不包含:BringIntoView 方法

ItemsPresenter中不包含:ApplyTemplate 方法

ControlTemplate中不包含:FindName 方法

Silverlight中的问题仍然没有解决!目前知道一种方法可以定位到节点,但是这种方法在实际的项目中可能并不使用。

1、先将第一层的节点的IsExpanded设置为true

2、递归的方式将节点的IsExpanded设置为true,然后就可以通过遍历DataContext的属性进行访问。

结果最好的方法是

I ran into this same problem. I needed to get to the TreeViewItem so that I could have it be selected. I then realized that I could just add a property IsSelected to my ViewModel, which I then bound to the TreeViewItems IsSelectedProperty. This can be achieved with the ItemContainerStyle:

<TreeView><TreeView.ItemContainerStyle><StyleTargetType="{x:Type TreeViewItem}"><Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/><Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/></Style></TreeView.ItemContainerStyle></TreeView>

Now if I want to have an item in the treeview selected, I just call IsSelected on my ViewModel class directly.

Hope it helps someone.

Done.

转载于:https://www.cnblogs.com/wangn/archive/2013/06/13/3133969.html

WPF TreeViewItem相关推荐

  1. Wpf TreeView根据SelectedItem找选中的TreeViewItem

    1. SelectedItem是绑定的DataContext 对象 2. Items是绑定对象集合 两层节点的查找方法,可递归扩展多层 // 从第一root节点查找TreeViewItem selec ...

  2. WPF and Silverlight 学习笔记(十):WPF控件模型

    WPF对控件其类型的继承方式如下 (其中绿色表示的类是抽象类,蓝色表示的类是非抽象类) 控件内容模型      System.Windows.Controls.Control类:表示 用户界面 (UI ...

  3. WPF TreeView HierarchicalDataTemplate

    原文 WPF TreeView HierarchicalDataTemplate   <StackPanel Margin="0,0,0,0"><StackPan ...

  4. 分享Silverlight/WPF/Windows Phone一周学习导读(10月1日-10月15日)

    分享Silverlight/WPF/Windows Phone一周学习导读(10月1日-10月15日) 本周Silverlight学习资源更新: [Silverlight入门系列]ListboxIte ...

  5. WPF拖放功能实现zz

    写在前面:本文为即兴而作,因此难免有疏漏和词不达意的地方.在这里,非常期望您提供评论,分享您的想法和建议. 这是一篇介绍如何在WPF中实现拖放功能的短文. 首先要读者清楚的一件事情是:拖放主要分为拖放 ...

  6. WPF中触发器Trigger、MultiTrigger、DataTrigger、MultiDataTrigger、EventTrigger几种

    WPF中有种叫做触发器的东西(记住不是数据库的trigger哦).它的主要作用是根据trigger的不同条件来自动更改外观属性,或者执行动画等操作. WPFtrigger的主要类型有:Trigger. ...

  7. 潜移默化学会WPF(难点控件treeview)--改造TreeView(CheckBox多选择版本),递归绑定数据...

    目前自己对treeview的感慨很多 今天先讲 面对这种 表结构的数据 的其中一种绑定方法,后面多几列其他属性都没关系,例如多个字段, 1  A  0 2  B  0 3  C  0 4  D  1 ...

  8. WPF 自定义列表筛选 自定义TreeView模板 自定义ListBox模板

    有很多项目,都有数据筛选的操作.下面提供一个案例,给大家做参考. 左侧是数据源,搜索框加TreeView控件,右侧是ListBox控件.在左侧数据列点击添加数据,然后点击确定,得到所筛选的数据. 下面 ...

  9. WPF模板(二)应用

    原文:WPF模板(二)应用 本次内容来源于电子书,和上一篇一样. 在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中Control ...

最新文章

  1. Wt::WPaintDevice
  2. Python 数据类型及其用法
  3. 重载函数与函数模板(转)
  4. PHPcms v9 get标签sql 语句limit无效问题的解决方法
  5. webstorm基础使用总结
  6. MySQL 中NULL和空值的区别
  7. SAP ABAP 平台新的编程模型
  8. github issue 搜索_回顾 2020 年 GitHub 的大事件,你知道多少?
  9. oracle的ora01504,Oracle中的ORA-01548: active rollback segment '_SYSSMU1$' found
  10. android view设置按钮颜色_Android 酷炫自定义 View:高仿 QQ 窗帘菜单
  11. ZeroMQ接口函数之 :zmq_proxy – 开始ZMQ内置代理
  12. BCB 第三方组件/控件 ZZ
  13. 深度感知解决方案 | 深度摄像头的三种主流技术优劣对比
  14. smbian c++生成sis文件日记
  15. HTML嵌套Flash播放视频
  16. PDF中几个的空白页怎么删除?
  17. 引入jquery不起作用 原因
  18. 用jQuery--实现todolist待办事项清单
  19. android输入法01:SoftKeyboard源码解析02
  20. 简单介绍如何应用【Poi-tl】将【个人简历】导出为【docx】格式的【word】文档

热门文章

  1. TypeScript内置对象
  2. ★LeetCode(108)——将有序数组转换为二叉搜索树(JavaScript)
  3. idea java mapper.xml文件sql黄色背景解决
  4. 【Vue】—列表渲染v-for指令
  5. mysql 时间段内的周末_淘宝用户行为数据分析(MySQL)
  6. python复制文件到指定文件夹_python 拷贝文件夹下所有的文件到指定文件夹(不包括目录)...
  7. android 前后同时预览_用上这些官方动态壁纸,让你的 Android 主屏简洁又优雅
  8. 我想说进厂打工怎么就丢人了
  9. 那些不用上班的老人每天是不是很幸福?
  10. 《西游记》中九尾狐狸为什么有太上老君的幌金绳?