How to find a control with a specific name in an XAML UI with C# code?
Asked Answered
B

4

9

I have dynamic added controls in my XAML UI. How I can find a specific control with a name.

Blackmail answered 29/6, 2016 at 22:17 Comment(0)
S
16

There is a way to do that. You can use the VisualTreeHelper to walk through all the objects on the screen. A convenient method I use (obtained it somewhere from the web) is the FindControl method:

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;
}

You can use it like this:

var combo = ControlHelper.FindControl<ComboBox>(this, typeof(ComboBox), "ComboBox123");
Sansone answered 30/6, 2016 at 16:59 Comment(2)
Would FindName also work?Edwyna
Thank you, Martin! For someone who needs get access from code to any DataTemplate controls just use Tag to keep dynamicly created name and modify code above for check the control Tag property.Trimetallic
S
4

I have extended @Martin Tirion version, to make it comfortable:

  • Eliminate the type parameter
  • Make UIElement extension for better use

Here is the changed code:

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;
        }
    }
}

After the modification, I am able to use like this:

var combo = parent.FindControl<ComboBox>("ComboBox123");

or when the parent is the current dialog it just like this:

var combo = FindControl<ComboBox>("ComboBox123");

Thank you @Martin Tirion again!

Sneakbox answered 25/9, 2019 at 5:17 Comment(0)
R
1

When you create the Control in XAML you can give it a x:Name="..." Tag. In your corresponding C# Class the Control will be available under that name.
Some Container Views like Grid got a Children Property, you can use this to search for Controls inside them.

Rader answered 30/6, 2016 at 12:57 Comment(1)
This is the answer.Clatter
S
0

I liked the previous answers, but I wanted some control if it would walk the tree and allow for it not to find the control.

Usage:

/// <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;
        }
    }
}

The extension 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;
    }
}
Stokowski answered 30/8, 2021 at 8:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.