8

When I iterate over a bunch of different controls on a Form, instead of trying to access the Text property:

String text = String.Empty;
foreach(Control control in this.Controls)
{
   try
   {
      text = control.Text;
   }
   catch(Exception exception)
   {
      // This control probably doesn't have the Text property.
      Debug.WriteLine(exception.Message);
   }
}

Is there a way to just determine whether or not a given control has a Text property? Something like this:

String text = String.Empty;
foreach(Control control in this.Controls)
{
   if(control has Text property)
   {
      text = control.Text;
   }
}

I absolutely despise the Try/Catch blocks (unless there is no better alternative, of-course).

Grim
  • 672
  • 4
  • 17
James
  • 167
  • 1
  • 3
  • 11
  • You can use reflection, but is there just a specific type of control(s) that you need? You can do `if (control is TextBox || control is Label)` – Adam Plocher Mar 05 '13 at 23:58
  • Yeah, I have many Custom controls some do not have the Text property, and some do. Also, any (standard) control that you see in the Toolbox in VS, is (or may be - depending on what the user is creating) on a form. While I could use your approach, there are still many other standard controls that have the Text property - and if they have it, I'll be needing it. :-) – James Mar 06 '13 at 00:03
  • 1
    ANY object derived from Control has a property called Text. – Steve Mar 06 '13 at 00:05
  • 1
    @JasonVoorhees All objects derived from `Control` have a `Text` property. If they hadn't, your code would not compile. However, the property is hidden in the designer for controls that don't support it. Even when your custom controls don't override the `Text` property, it still exist. – Daniel A.A. Pelsmaeker Mar 06 '13 at 00:08
  • @Steve, you are right - I simply over-generalised when I said "custom _controls_" – James Mar 06 '13 at 00:08
  • @Virtlink - Oh, okay. I understand now. I thought that the ones that didn't show it just didn't have it. I forgot that all objects derived from Control have a Text property. – James Mar 06 '13 at 00:13
  • @Virtlink could you give me an example of a non-custom control that throws an exception when accessing the `Text` property? – Oscar Mederos Mar 06 '13 at 00:14
  • @OscarMederos: Here you go: `Error 1 'System.Windows.Forms.MainMenu' does not contain a definition for 'Text' and no extension method 'Text' accepting a first argument of type 'System.Windows.Forms.MainMenu' could be found (are you missing a using directive or an assembly reference?) c:\users\documents\visual studio 2012\Projects\fg\fg\Form1.cs 26 27 fg` – James Mar 06 '13 at 00:47
  • 1
    @JasonVoorhees `System.Windows.Forms.MainMenu` does not inherit from `Control`. I thought you were talking about `Control` instances. – Oscar Mederos Mar 06 '13 at 01:58
  • I don't know right now to be honest. I think I need to get some sleep before I say any more silly things. :-/ – James Mar 06 '13 at 02:09

3 Answers3

8

All Control objects have a Text property, so there is no point in using reflection to determine that. It will always return true.

Your problem actually is that some controls throw an exception from their Text property because they don't support it.

If you also want to be able to use custom controls that you don't know in advance, you should stick to your current solution and catch the exceptions. However, you should catch the specific exception thrown, for example NotSupportedException.

If you only ever encounter controls that you know in advance, you can select the controls that you know have a working Text property. For example:

public static bool HasWorkingTextProperty(Control control)
{
    return control is Label
        || control is TextBox
        || control is ComboBox;
}

var controlsWithText = from c in this.Controls
                       where HasWorkingTextProperty(c)
                       select c;

foreach(var control in controlsWithText)
{
    string text = control.Text;
    // Do something with it.
}

And if you implement your own custom controls that may or may not have a Text property, then you can derive them from a base class that indicates this:

public abstract class CustomControlBase : Control
{
    public virtual bool HasText
    {
        get { return false; }
    }
}

public class MyCustomControl : CustomControlBase
{
    public override bool HasText
    {
        get { return true; }
    }

    public override string Text
    {
        get { /* Do something. */ }
        set { /* Do something. */ }
    }
}

public static bool HasWorkingTextProperty(Control control)
{
    return (control is CustomControlBase && ((CustomControlBase)control).HasText)
        || control is Label
        || control is TextBox
        || control is ComboBox;
}
Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
6

Your question is How to determine if Control has Text property, so here is how you can do it using Reflection:

control.GetType().GetProperties().Any(x => x.Name == "Text");

Edit: If you take a look at the Control class, you will see it has a Text property.

Now, if some custom control that overrides the Control class throws an exception when accessing to the Text property, it is violating the Liskov substitution principle. In that case, I suggest you identifying those controls, although what you're doing seems to be fine.

Oscar Mederos
  • 29,016
  • 22
  • 84
  • 124
3

Check this out:

private void Form1_Load(object sender, EventArgs e)
{
     foreach (Control ctrl in this.Controls)
     {
          PropertyInfo[] properties = ctrl.GetType().GetProperties();
          foreach(PropertyInfo pi in properties)
              if (pi.Name == "Text")
              { 
                    //has text
              }
       }

}
Hanlet Escaño
  • 17,114
  • 8
  • 52
  • 75