如何在WPF中的ComboBox
MyContainer
中获取Grid
类型的子控件?
<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>
这一行给了我一个错误:
var myCombobox = this.MyContainer.Children.GetType(ComboBox);
答案 0 :(得分:73)
此扩展方法将递归搜索所需类型的子元素:
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;
}
所以使用它你可以要求MyContainer.GetChildOfType<ComboBox>()
。
答案 1 :(得分:37)
儿童是UIElements的集合。因此,您需要迭代项目并确定每个项目是否属于所需类型。幸运的是,已经有一种Linq方法,即Enumerable.OfType<T>
,您可以使用Extension Method语法方便地调用它:
var comboBoxes = this.MyContainer.Children.OfType<ComboBox>();
此方法根据类型过滤集合,并在您的情况下仅返回ComboBox
类型的元素。
如果您只想要第一个ComboBox(正如您的变量名可能建议的那样),您只需将FirstOrDefault()
的调用附加到查询中:
var myComboBox = this.MyContainer.Children.OfType<ComboBox>().FirstOrDefault();
答案 2 :(得分:2)
搜索包含预定点(屏幕)的特定类型的第一个孩子:
(param'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;
}
答案 3 :(得分:2)
所有这些答案中,只有一个使用了 IMO 只是strong脚的递归:)
获取视觉儿童:
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);
}
}
}
获取有逻辑的孩子:
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);
}
}
}
请注意,如果您希望在第一次遇到时都停下来,那么这两个深度遍历的树都应更改两个代码,以将对queue.Enqueue
的调用包含在else
块中。
答案 4 :(得分:0)
所有这些答案都非常好,但是,如果您正在尝试找到类型为T的特定视觉孩子,那么您可能会陷入困境,然后再找到它们你想要的那个,或者希望你得到的第一个是你想要的那个。我合并了一些方法,根据标准找到一个特定的方法。它有点像LINQ,但我并不想尝试处理递归的枚举器。
像这样使用:
MyContainer.FirstOrDefaultChild<Label>(l => l.Content=="State")
我把它写成了一种扩展方法。
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;
}
答案 5 :(得分:-1)
我找到了这个工作示例:
foreach (object o in LogicalTreeHelper.GetChildren(myWindow))
{
if (o is SomeTypeOfMine)
{
//do something
}
}