1

I have a UserControl that have a few child UserControl's and those UserControl's have child UserControl's.

Consider this:

MainUserControl
  TabControl
    TabItem
      UserControl
        UserControl
          UserControl : ISomeInterface
    TabItem
      UserControl
        UserControl
          UserControl : ISomeInterface
    TabItem
      UserControl
        UserControl
          UserControl : ISomeInterface
    TabItem
      UserControl
        UserControl
          UserControl : ISomeInterface

This is what i have so far, but finds no ISomeInterface:

PropertyInfo[] properties = MainUserControl.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
    if (typeof(ISomeInterface).IsAssignableFrom(property.PropertyType))
    {
        property.GetType().InvokeMember("SomeMethod", BindingFlags.InvokeMethod, null, null, null);
    }
}

Is it possible so find all the child UserControl's from MainUserControl that implement ISomeInterface via reflection and call a method(void SomeMethod()) on that interface?

Willem
  • 9,166
  • 17
  • 68
  • 92
  • 2
    Why do you think GetProperties() method would go down recursively? You are enumerating the properties of the type, not the whole controls hierarchy. Consider enumerating Controls collection instead. – Alexander Tsvetkov Apr 01 '13 at 10:04

2 Answers2

5

You will need to recursively iterate through all the subcontrols within your MainUserControl.

Here's a helper method you can use:

/// <summary>
/// Recursively lists all controls under a specified parent control.
/// Child controls are listed before their parents.
/// </summary>
/// <param name="parent">The control for which all child controls are returned</param>
/// <returns>Returns a sequence of all controls on the control or any of its children.</returns>

public static IEnumerable<Control> AllControls(Control parent)
{
    if (parent == null)
    {
        throw new ArgumentNullException("parent");
    }

    foreach (Control control in parent.Controls)
    {
        foreach (Control child in AllControls(control))
        {
            yield return child;
        }

        yield return control;
    }
}

Then:

foreach (var control in AllControls(MainUserControl))
{
    PropertyInfo[] properties = control.GetType().GetProperties();
    ... Your loop iterating over properties

Or (much better if this will work for you, since it's a lot simpler):

foreach (var control in AllControls(MainUserControl))
{
    var someInterface = control as ISomeInterface;

    if (someInterface != null)
    {
        someInterface.SomeMethod();
    }
}

Or, using Linq (need a using System.Linq to do this):

foreach (var control in AllControls(MainUserControl).OfType<ISomeInterface>())
    control.SomeMethod();

Which seems best of all. :)

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • 2
    Maybe you could add using the `is` operator. OP seems to be in the direction of using reflection while dynamic casting is much easier (and cheaper) (or am I missing something too?) – bas Apr 01 '13 at 10:10
  • Yeah, that was what I meant. Already upvoted but imaginary +2 then :) – bas Apr 01 '13 at 10:17
  • 1
    System.Windows.Controls.Control doesn't have a Controls property?! – Diego Frehner Jun 18 '13 at 14:09
  • @DiegoFrehner You are correct - `.Controls` is for `Windows.Forms.Control`! For WPF we'd need to use VisualTreeHelper [as described here](http://stackoverflow.com/questions/14875042/finding-all-child-controls-wpf). I'm not sure why the OP didn't say anything about that... – Matthew Watson Jun 18 '13 at 14:38
3

Maybe I am looking in the wrong direction myself. What I meant with the comment on Matthews answer was:

 foreach (var control in AllControls(MainUserControl))
 {
     if (control is ISomeInterface)
     {

     }
 }

or

 foreach (var control in AllControls(MainUserControl))
 {
     var someInterface = control as ISomeInterface;
     if (someInterface != null)
     {
          someInterface.SomeMethod();
     }
 }
bas
  • 13,550
  • 20
  • 69
  • 146