Search code examples
c#wpfgenericsvisualtreehelper

How to make method, that finds sepcific type of child user control, more generic?


I have some few cases in my WPF application that requires me to find a specific type of user control in a given user control. For example I'm having the following method that already works nicely:

    public static System.Windows.Controls.CheckBox FindChildCheckBox(DependencyObject d)
    {
        try
        {
            System.Windows.Controls.CheckBox chkBox = d as System.Windows.Controls.CheckBox;

            if (d != null && chkBox == null)
            {
                int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(d);
                for (int i = 0; i < count; i++)
                {
                    chkBox = FindChildCheckBox(System.Windows.Media.VisualTreeHelper.GetChild(d, i));
                    if (chkBox != null)
                        break;
                }
            }

            return chkBox;
        }
        catch
        {
            return null;
        }
    }

This method will help me to find a CheckBox in a given ListViewItem which allows me to check/uncheck the said CheckBox more conveniently.

However, I'd like to have this method more generic like for example:

public static T FindChildUserControl<T>(DependencyObject d)

Unfortunately I do not see how I can get this work. Can someone please help?


Solution

  • You need to replace CheckBox with T and add a generic restraint (where) to the type argument.

    For example I'm having the following method that already works nicely

    Which is odd, as far as I can tell it would only work on nested CheckBoxes. This should on any combination of controls:

    public static T FindChild<T>(DependencyObject d) where T : DependencyObject
    {
        if (d is T)
            return (T)d;
    
        int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(d);
        for (int i = 0; i < count; i++)
        {
            DependencyObject child = FindChild<T>(System.Windows.Media.VisualTreeHelper.GetChild(d, i));
            if (child != null)
                return (T)child;
        }
    
        return null;
    }
    

    Usage:

    CheckBox check = FindChild<CheckBox>(parent);
    

    To get all children of a certain type, this should work nicely:

    public static IEnumerable<T> FindChildren<T>(DependencyObject d) where T : DependencyObject
    {
        if (d is T)
            yield return (T)d;
    
        int count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(d);
        for (int i = 0; i < count; i++)
        {
            foreach (T child in FindChildren<T>(System.Windows.Media.VisualTreeHelper.GetChild(d, i)))
                yield return child;
        }
    }
    

    Usage:

    foreach(CheckBox c in FindChildren<CheckBox>(parent))
    

    This method will help me to find a CheckBox in a given ListViewItem which allows me to check/uncheck the said CheckBox more conveniently.

    You should use MVVM instead. Walking down the VisualTree is a really hacky workaround.