整理一下项目中常用的找控件功能,包括找父/子控件、找到所有同类型子控件(比如ListBox找到所有Item)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
namespace MyDemo.Utils
{
/// <summary>
/// 用于查找控件的工具类:找到父控件、子控件
/// </summary>
class ControlsSearchHelper
{
/// <summary>
/// 查找父控件
/// </summary>
/// <typeparam name="T">父控件的类型</typeparam>
/// <param name="obj">要找的是obj的父控件</param>
/// <param name="name">想找的父控件的Name属性</param>
/// <returns>目标父控件</returns>
public static T GetParentObject<T>(DependencyObject obj, string name) where T : FrameworkElement
{
DependencyObject parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name)))
{
return (T)parent;
}
// 在上一级父控件中没有找到指定名字的控件,就再往上一级找
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
/// <summary>
/// 查找子控件
/// </summary>
/// <typeparam name="T">子控件的类型</typeparam>
/// <param name="obj">要找的是obj的子控件</param>
/// <param name="name">想找的子控件的Name属性</param>
/// <returns>目标子控件</returns>
public static T GetChildObject<T>(DependencyObject obj, string name) where T : FrameworkElement
{
DependencyObject child = null;
T grandChild = null;
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name)))
{
return (T)child;
}
else
{
// 在下一级中没有找到指定名字的子控件,就再往下一级找
grandChild = GetChildObject<T>(child, name);
if (grandChild != null)
return grandChild;
}
}
return null;
}
/// <summary>
/// 获取所有同一类型的子控件
/// </summary>
/// <typeparam name="T">子控件的类型</typeparam>
/// <param name="obj">要找的是obj的子控件集合</param>
/// <param name="name">想找的子控件的Name属性</param>
/// <returns>子控件集合</returns>
public static List<T> GetChildObjects<T>(DependencyObject obj, string name) where T : FrameworkElement
{
DependencyObject child = null;
List<T> childList = new List<T>();
for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++)
{
child = VisualTreeHelper.GetChild(obj, i);
if (child is T && (((T)child).Name == name || string.IsNullOrEmpty(name)))
{
childList.Add((T)child);
}
childList.AddRange(GetChildObjects<T>(child, ""));
}
return childList;
}
}
}
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
yield return (T)child;
foreach (T childOfChild in FindVisualChildren<T>(child))
yield return childOfChild;
}
}
}
小结:
- 采用了递归的方式,在多级中去查找指定Name属性的父控件/子控件。如果不想指定名字,或者只想在上/下一级中查找(不递归),根据需求再稍作修改。
- 虽说这是用的WPF的查找方式,依赖的库很多无法跨平台,但是这种递归查找的方式值得学习和借鉴。(例如以后做Unity项目时可以拿来参考)