Silverlight 中有所谓视觉树 (Visual Tree)的概念,而 VisualTree 是一个运行时的概念,其实可以理解为一种 DOM.
其内容的来源可以是几个方面:
- 静态 XAML 文件中创建的。
- 用 XamlReadler.Load() 方法动态加载的 XAML 内容。
- 完全通过代码创建的控件。
在 XAML 中我们通过 x:Name 来标识一个元素,但是光靠 Name 不能解决全部的问题,特别对于一些动态的场景而言。
有时候我们还需要根据控件的类型或者其他条件来查找节点。
比如:
“给我找出当前这个控件在哪个 Tab 页( TabItem)中 ”
“找出祖先控件中谁实现了 IDialogHost 接口(准备显示一个对话框加载当前用户控件的内容) ”
等等类似的需求。
于是就有了下面两个方法:
using System.Collections.Generic; using System.Windows; using System.Windows.Media; namespace NeilChen.SilverlightExtensions { public static class DomExtensions { /// <summary> /// 查找祖先节点 /// </summary> /// <typeparam name="T">目标节点的类型</typeparam> /// <param name="child">起始节点</param> /// <returns></returns> public static T FindAncestor<T>(this DependencyObject child) where T : class { var d = VisualTreeHelper.GetParent(child); while (d != null && !(d is T)) { d = VisualTreeHelper.GetParent(d); } return d as T; } /// <summary> /// 查找某种类型的子孙节点 /// </summary> /// <typeparam name="T">目标节点类型</typeparam> /// <param name="parent">起始节点</param> /// <returns>符合条件的节点集合</returns> public static IEnumerable<T> FindChildren<T>(this DependencyObject parent) where T : class { var count = VisualTreeHelper.GetChildrenCount(parent); if (count > 0) { for (var i = 0; i < count; i++) { var child = VisualTreeHelper.GetChild(parent, i); var t = child as T; if (t != null) yield return t; var children = FindChildren<T>(child); foreach (var item in children) yield return item; } } } } }
使用方法很简单。比如(还是拿对话框来举例):
IDialogHost host = this.FindAncestor<IDialogHost>(); if (host != null) { host.ShowModalDialog(this); } REF:http://msdn.microsoft.com/zh-cn/library/dd391781.aspx