如何使用 C# 代码在 XAML UI 中查找具有特定名称的控件?
How to find a control with a specific name in an XAML UI with C# code?
我的 XAML UI 中有动态添加的控件。
如何找到具有名称的特定控件。
当您在 XAML 中创建控件时,您可以给它一个 x:Name="..."
标签。在相应的 C# Class 中,控件将以该名称提供。
一些像 Grid 这样的容器视图有一个 Children
属性,你可以用它来搜索里面的控件。
有办法做到这一点。您可以使用 VisualTreeHelper
遍历屏幕上的所有对象。我使用的一种方便的方法(从网上某处获得)是 FindControl
方法:
public static T FindControl<T>(UIElement parent, Type targetType, string ControlName) where T : FrameworkElement
{
if (parent == null) return null;
if (parent.GetType() == targetType && ((T)parent).Name == ControlName)
{
return (T)parent;
}
T result = null;
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (FindControl<T>(child, targetType, ControlName) != null)
{
result = FindControl<T>(child, targetType, ControlName);
break;
}
}
return result;
}
你可以这样使用它:
var combo = ControlHelper.FindControl<ComboBox>(this, typeof(ComboBox), "ComboBox123");
我扩展了@Martin Tirion 版本,让它更舒适:
- 消除类型参数
- 制作 UIElement 扩展以便更好地使用
这是更改后的代码:
namespace StackOwerflow.Sample.Helpers
{
public static class UIElementExtensions
{
public static T FindControl<T>( this UIElement parent, string ControlName ) where T : FrameworkElement
{
if( parent == null )
return null;
if( parent.GetType() == typeof(T) && (( T )parent).Name == ControlName )
{
return ( T )parent;
}
T result = null;
int count = VisualTreeHelper.GetChildrenCount( parent );
for( int i = 0; i < count; i++ )
{
UIElement child = ( UIElement )VisualTreeHelper.GetChild( parent, i );
if( FindControl<T>( child, ControlName ) != null )
{
result = FindControl<T>( child, ControlName );
break;
}
}
return result;
}
}
}
修改后可以这样使用了:
var combo = parent.FindControl<ComboBox>("ComboBox123");
或者当父对话框是当前对话框时,就像这样:
var combo = FindControl<ComboBox>("ComboBox123");
再次感谢@Martin Tirion!
我喜欢以前的答案,但我想要一些控制,如果它会遍历树并允许它找不到控制。
用法:
/// <summary>
/// Finds a grid panel with the name "GridVariables" and toggles it's visibility to and from visible
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public sealed partial class MainPage : Page
{
private void btnShowVariables_Click(object sender, RoutedEventArgs e)
{
if (this.TryFindChildControl<Grid>("gridVariables", out var grid))
{
grid.Visibility = grid.Visibility.HasFlag(Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed;
}
}
}
分机 class:
public static class UIElementExtensions
{
/// <summary>
/// Returns the first FrameworkElement with the type and name
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sourceControl"></param>
/// <param name="name"></param>
/// <param name="control"></param>
/// <returns></returns>
public static bool TryFindChildControl<T>(this UIElement sourceControl, string name, out T control, bool recursiveSearch = true)
where T : FrameworkElement
{
var childCount = VisualTreeHelper.GetChildrenCount(sourceControl);
for (var c = 0; c < childCount; c++)
{
var child = VisualTreeHelper.GetChild(sourceControl, c) as FrameworkElement;
if (child == null) continue;
var castChild = child as T;
var found = castChild != null && castChild.Name.ToLower() == name.ToLower();
if (!found)
{
if (recursiveSearch && TryFindChildControl<T>(child, name, out var innerChild, recursiveSearch))
{
castChild = innerChild;
}
else
{
continue;
}
}
control = castChild;
return true;
}
control = null;
return false;
}
}
我的 XAML UI 中有动态添加的控件。 如何找到具有名称的特定控件。
当您在 XAML 中创建控件时,您可以给它一个 x:Name="..."
标签。在相应的 C# Class 中,控件将以该名称提供。
一些像 Grid 这样的容器视图有一个 Children
属性,你可以用它来搜索里面的控件。
有办法做到这一点。您可以使用 VisualTreeHelper
遍历屏幕上的所有对象。我使用的一种方便的方法(从网上某处获得)是 FindControl
方法:
public static T FindControl<T>(UIElement parent, Type targetType, string ControlName) where T : FrameworkElement
{
if (parent == null) return null;
if (parent.GetType() == targetType && ((T)parent).Name == ControlName)
{
return (T)parent;
}
T result = null;
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (FindControl<T>(child, targetType, ControlName) != null)
{
result = FindControl<T>(child, targetType, ControlName);
break;
}
}
return result;
}
你可以这样使用它:
var combo = ControlHelper.FindControl<ComboBox>(this, typeof(ComboBox), "ComboBox123");
我扩展了@Martin Tirion 版本,让它更舒适:
- 消除类型参数
- 制作 UIElement 扩展以便更好地使用
这是更改后的代码:
namespace StackOwerflow.Sample.Helpers
{
public static class UIElementExtensions
{
public static T FindControl<T>( this UIElement parent, string ControlName ) where T : FrameworkElement
{
if( parent == null )
return null;
if( parent.GetType() == typeof(T) && (( T )parent).Name == ControlName )
{
return ( T )parent;
}
T result = null;
int count = VisualTreeHelper.GetChildrenCount( parent );
for( int i = 0; i < count; i++ )
{
UIElement child = ( UIElement )VisualTreeHelper.GetChild( parent, i );
if( FindControl<T>( child, ControlName ) != null )
{
result = FindControl<T>( child, ControlName );
break;
}
}
return result;
}
}
}
修改后可以这样使用了:
var combo = parent.FindControl<ComboBox>("ComboBox123");
或者当父对话框是当前对话框时,就像这样:
var combo = FindControl<ComboBox>("ComboBox123");
再次感谢@Martin Tirion!
我喜欢以前的答案,但我想要一些控制,如果它会遍历树并允许它找不到控制。
用法:
/// <summary>
/// Finds a grid panel with the name "GridVariables" and toggles it's visibility to and from visible
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public sealed partial class MainPage : Page
{
private void btnShowVariables_Click(object sender, RoutedEventArgs e)
{
if (this.TryFindChildControl<Grid>("gridVariables", out var grid))
{
grid.Visibility = grid.Visibility.HasFlag(Visibility.Collapsed) ? Visibility.Visible : Visibility.Collapsed;
}
}
}
分机 class:
public static class UIElementExtensions
{
/// <summary>
/// Returns the first FrameworkElement with the type and name
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="sourceControl"></param>
/// <param name="name"></param>
/// <param name="control"></param>
/// <returns></returns>
public static bool TryFindChildControl<T>(this UIElement sourceControl, string name, out T control, bool recursiveSearch = true)
where T : FrameworkElement
{
var childCount = VisualTreeHelper.GetChildrenCount(sourceControl);
for (var c = 0; c < childCount; c++)
{
var child = VisualTreeHelper.GetChild(sourceControl, c) as FrameworkElement;
if (child == null) continue;
var castChild = child as T;
var found = castChild != null && castChild.Name.ToLower() == name.ToLower();
if (!found)
{
if (recursiveSearch && TryFindChildControl<T>(child, name, out var innerChild, recursiveSearch))
{
castChild = innerChild;
}
else
{
continue;
}
}
control = castChild;
return true;
}
control = null;
return false;
}
}