C# 如何按类型获取 WPF 容器的子级?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10279092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get children of a WPF container by type?
提问by ArchieTiger
How can I get the child controls of type ComboBoxin MyContainerGridin WPF?
如何在 WPF 中获取类型ComboBox为MyContainerGridin的子控件?
<Grid x:Name="MyContainer">
<Label Content="Name" Name="label1" />
<Label Content="State" Name="label2" />
<ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox1"/>
<ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox3" />
<ComboBox Height="23" HorizontalAlignment="Left" Name="comboBox4" />
</Grid>
This line gives me an error:
这一行给了我一个错误:
var myCombobox = this.MyContainer.Children.GetType(ComboBox);
采纳答案by Matt Hamilton
This extension method will search recursively for child elements of the desired type:
此扩展方法将递归搜索所需类型的子元素:
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
So using that you can ask for MyContainer.GetChildOfType<ComboBox>().
所以使用它你可以要求MyContainer.GetChildOfType<ComboBox>().
回答by Botz3000
Children is a collection of UIElements. So you need to iterate over the items and determine for each item whether it is of the required type. Fortunately, there is already a Linq method for exactly this, namely Enumerable.OfType<T>, which you can conveniently call using Extension Methodsyntax:
Children 是 UIElements 的集合。因此,您需要遍历项目并确定每个项目是否属于所需类型。幸运的是,已经有一个 Linq 方法,即Enumerable.OfType<T>,您可以使用扩展方法语法方便地调用它:
var comboBoxes = this.MyContainer.Children.OfType<ComboBox>();
This method filters the collection based on their type and returns, in your case, only the elements of type ComboBox.
此方法根据集合的类型过滤集合,并在您的情况下仅返回 type 的元素ComboBox。
If you only want the first ComboBox (as your variable name might suggest), you can just append a call to FirstOrDefault()to the query:
如果您只想要第一个 ComboBox(正如您的变量名称所暗示的那样),您可以将调用附加FirstOrDefault()到查询中:
var myComboBox = this.MyContainer.Children.OfType<ComboBox>().FirstOrDefault();
回答by ale
Search for the first child of a certain type that includes a predetermined point (of Screen):
搜索包含预定点(屏幕)的特定类型的第一个子项:
(param 'point' is the result of calling 'PointToScreen' function (declared in Visual type) )
(参数 'point' 是调用 'PointToScreen' 函数的结果(在 Visual 类型中声明))
private TDescendantType FindDescendant<TDescendantType>(DependencyObject parent, Point screenPoint)
where TDescendantType : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is Visual)
{
Point point = ((Visual)child).PointFromScreen(screenPoint);
Rect rect = VisualTreeHelper.GetDescendantBounds((Visual)child);
if (!rect.Contains(point))
continue;
}
if (child is TDescendantType)
{
return (TDescendantType)child;
}
child = FindDescendant<TDescendantType>(child, screenPoint);
if (child != null)
{
return (TDescendantType)child;
}
}
return null;
}
回答by Reginald Blue
All of these answers are very nice, but, if you're trying to find a specificvisual child of type T, you're either stuck getting them all and then finding the one you want, or hoping the first one you get is the one you want. I merged a few approaches to find a specific one based on a criteria. It's a bit like LINQ, but I didn't want to try to deal with a recursive enumerator.
所有这些答案都非常好,但是,如果您试图找到T 类型的特定视觉子项,那么您要么被困在获取所有它们然后找到您想要的那个,要么希望您得到的第一个是你想要的。我合并了几种方法以根据标准找到特定的方法。它有点像 LINQ,但我不想尝试处理递归枚举器。
Use it like this:
像这样使用它:
MyContainer.FirstOrDefaultChild<Label>(l => l.Content=="State")
I wrote it as an extension method.
我把它写成一个扩展方法。
public static class DependencyObjectExtensions
{
public static T FirstOrDefaultChild<T>(this DependencyObject parent, Func<T, bool> selector)
where T : DependencyObject
{
T foundChild;
return FirstOrDefaultVisualChildWhere(parent, selector, out foundChild) ? foundChild : default(T);
}
private static bool FirstOrDefaultVisualChildWhere<T>(DependencyObject parent, Func<T, bool> selector,
out T foundChild) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
var tChild = child as T;
if (tChild != null)
{
if (!selector(tChild)) continue;
foundChild = tChild;
return true;
}
if (FirstOrDefaultVisualChildWhere(child, selector, out foundChild))
{
return true;
}
}
foundChild = default(T);
return false;
}
回答by Aybe
All of these answers but one uses recursion which IMOis just lame :)
所有这些答案,但一个使用递归,IMO只是蹩脚的:)
Get visual children:
获得视觉儿童:
public static IEnumerable<T> FindVisualChildren<T>([NotNull] this DependencyObject parent) where T : DependencyObject
{
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var queue = new Queue<DependencyObject>(new[] {parent});
while (queue.Any())
{
var reference = queue.Dequeue();
var count = VisualTreeHelper.GetChildrenCount(reference);
for (var i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(reference, i);
if (child is T children)
yield return children;
queue.Enqueue(child);
}
}
}
Get logical children:
获取逻辑孩子:
public static IEnumerable<T> FindLogicalChildren<T>([NotNull] this DependencyObject parent) where T : DependencyObject
{
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var queue = new Queue<DependencyObject>(new[] {parent});
while (queue.Any())
{
var reference = queue.Dequeue();
var children = LogicalTreeHelper.GetChildren(reference);
var objects = children.OfType<DependencyObject>();
foreach (var o in objects)
{
if (o is T child)
yield return child;
queue.Enqueue(o);
}
}
}
Note that both deeply traverse trees, if you wish to stop at first encounter then change both codes to encompass the call to queue.Enqueuein an elseblock.
请注意,这两个深度遍历树,如果您希望在第一次遇到时停止,则更改两个代码以将调用包含queue.Enqueue在一个else块中。
回答by Hemant Surale
I found this working example:
我找到了这个工作示例:
foreach (object o in LogicalTreeHelper.GetChildren(myWindow))
{
if (o is SomeTypeOfMine)
{
//do something
}
}
来源:https: //social.msdn.microsoft.com/Forums/vstudio/en-US/e0be708a-5fa2-4479-b5a0-8ff44a963803/find-all-child-controls-of-a-type?forum=wpf

