我正在寻找一种方法,通过它们的类型在窗口上找到所有控件,
例如:找到所有的文本框,找到所有实现特定界面的控件等。
我正在寻找一种方法,通过它们的类型在窗口上找到所有控件,
例如:找到所有的文本框,找到所有实现特定界面的控件等。
当前回答
下面是另一个紧凑的版本,使用泛型语法:
public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null) {
if (obj is T)
yield return obj as T;
foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>())
foreach (T c in FindLogicalChildren<T>(child))
yield return c;
}
}
其他回答
要获得特定类型的所有子元素的列表,您可以使用:
private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
yield return obj;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
{
if (child != null)
{
yield return child;
}
}
}
}
yield break;
}
接受的答案返回发现的元素或多或少是无序的,方法是尽可能深入地跟随第一个子分支,同时在返回和重复尚未解析的树枝的步骤之前,沿途生成发现的元素。
如果你需要按降序排列的后代元素,其中直接的子元素将首先产生,然后是它们的子元素,依此类推,下面的算法将工作:
public static IEnumerable<T> GetVisualDescendants<T>(DependencyObject parent, bool applyTemplates = false)
where T : DependencyObject
{
if (parent == null || !(child is Visual || child is Visual3D))
yield break;
var descendants = new Queue<DependencyObject>();
descendants.Enqueue(parent);
while (descendants.Count > 0)
{
var currentDescendant = descendants.Dequeue();
if (applyTemplates)
(currentDescendant as FrameworkElement)?.ApplyTemplate();
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(currentDescendant); i++)
{
var child = VisualTreeHelper.GetChild(currentDescendant, i);
if (child is Visual || child is Visual3D)
descendants.Enqueue(child);
if (child is T foundObject)
yield return foundObject;
}
}
}
生成的元素将从最近到最远进行排序。 这将是有用的,例如,如果你正在寻找某种类型和条件的最近的子元素:
var foundElement = GetDescendants<StackPanel>(someElement)
.FirstOrDefault(o => o.SomeProperty == SomeState);
对于这个和更多的用例,你可以添加流动扩展方法到你的库:
public static List<DependencyObject> FindAllChildren(this DependencyObject dpo, Predicate<DependencyObject> predicate)
{
var results = new List<DependencyObject>();
if (predicate == null)
return results;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dpo); i++)
{
var child = VisualTreeHelper.GetChild(dpo, i);
if (predicate(child))
results.Add(child);
var subChildren = child.FindAllChildren(predicate);
results.AddRange(subChildren);
}
return results;
}
举个例子:
var children = dpObject.FindAllChildren(child => child is TextBox);
这是最简单的方法:
IEnumerable<myType> collection = control.Children.OfType<myType>();
其中控件是窗口的根元素。
编辑-正如评论中指出的那样。这只是一个层次的深度。查看一个更深入的选项的公认答案。
请注意,使用VisualTreeHelper仅适用于派生自Visual或Visual3D的控件。如果你还需要检查其他元素(例如TextBlock, FlowDocument等),使用VisualTreeHelper将抛出一个异常。
如果有必要,这里有一个回到逻辑树的替代方案:
http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways