0

This is probably a long shot, but I'm trying to minimize the repition in the program I'm working on, and have run into a snag. As can be seen in the ClearTextBoxes() method below, I have a very repetitive bit of code that I would prefer to place inside a foreach loop for succinctness. (Originally the foreach (object box in customBoxes) loop was not there). I tried to do this with the following List, but to no avail. I'm not sure if this is just not possible to do, or if I'm simply doing it wrong. I would appreciate any help you could give, and if this can't be done, then how can I shrink this code block?

Thanks!

List<object> customBoxes = new List<object>();

customBoxes.AddRange(new[] { "TextBox", "DateBox", "DigitBox", "PhoneBox", "WaterTextBox" });



public void ClearTextBoxes()
    {
        ChildControls ccChildren = new ChildControls();

        foreach (object o in ccChildren.GetChildren(rvraDockPanel, 2))
        {
            foreach (object box in customBoxes)
            {
                if (o.GetType() == typeof(TextBox))
                {
                    TextBox txt = (TextBox)o;
                    txt.Text = "";
                }

                if (o.GetType() == typeof(DigitBox))
                {
                    DigitBox digit = (DigitBox)o;
                    digit.Text = "";
                }

                if (o.GetType() == typeof(PhoneBox))
                {
                    PhoneBox phone = (PhoneBox)o;
                    phone.Text = "";
                }

                if (o.GetType() == typeof(DateBox))
                {
                    DateBox date = (DateBox)o;
                    date.Text = "";
                }

                if (o.GetType() == typeof(WatermarkTextBox))
                {
                    WatermarkTextBox water = (WatermarkTextBox)o;
                    water.Text = "";
                }
            }
        }
    }
Keven M
  • 972
  • 17
  • 47
  • 2
    I would inherit from each control and apply an interface with a ClearText() method. – James Nov 11 '11 at 06:49
  • what is role of second loop (foreach (object box in customBoxes) ) ? – DeveloperX Nov 11 '11 at 06:55
  • You could look at this question: http://stackoverflow.com/questions/619767/net-reflection-set-object-property – GTG Nov 11 '11 at 06:57
  • @James: Add that as an answer. – jgauffin Nov 11 '11 at 06:58
  • @DeveloperX: That loop was the beginning of trying to iterate through a foreach of the various types of boxes, so the goal was that it would condense all the "if(o.GetType() == typeof..." items. – Keven M Nov 11 '11 at 15:12

5 Answers5

1
List<Type> customBoxes = new List<Type>();

customBoxes.AddRange(new[] { typeof(PhoneBox), typeof(DigitBox), ....." });

foreach (Control c in this.Controls)
{
  if (customBoxes.Contains(c.GetType()))
  {
    c.Text = string.Empty;
  }
}
Damith
  • 62,401
  • 13
  • 102
  • 153
  • You should mention that this makes the (probably correct) assumption that all `customBoxes` inherit `Control` ... but the OP wasn't clear on this. – Scott Rippey Nov 11 '11 at 08:10
  • Sorry if I wasn't clear on that, but actually they don't inherit Control (at least I don't think they do). They inherit from the WatermarkTextBox in the ExtendedToolkit dll. And when I tried this approach the .Controls part gave an error that said there was no definition or extension method named controls. – Keven M Nov 11 '11 at 15:14
0

You could use reflection in some way to mimic some ductyping behavior but i wouldnt go for that solution since it's not performant and ugly.

        foreach (object box in customBoxes) 
        { 
            var boxType = box.GetType();
            var textProperty = boxType.GetProperty("Text");
            if (textProperty != null && textProperty.CanWrite)
            {
                textProperty.SetValue(box, "", null);
            }
        }

Or you can use dynamic to achieve the same result:

      foreach (dynamic box in customBoxes)
      {
           box.Text = "";
      }

The way to go would be to make your custom controls implement a single interface IWithTextProperty which ofcourse exposes the text property.

Polity
  • 14,734
  • 2
  • 40
  • 40
  • Reflection is something I've never even heard of until the last couple days searching posts. :) It's definitely something I need to look into though...same with dynamic. And I'm shaky on interfaces. Do you know of any very basic guides to interfaces anywhere? – Keven M Nov 11 '11 at 15:23
0

I would create an interface with a ClearText() method.

interface IClearable
{
  public void ClearText();
}

Then you can inherit from each control and apply that interface:

class ClearableDigitBox : DigitBox, IClearable
{
  public void ClearText() {
    Text = String.Empty;
  }
}
// etc...

So it's just:

var list = new List<IClearable>;
// ...
foreach (IClearable control in list) control.ClearText();
James
  • 7,343
  • 9
  • 46
  • 82
  • I tried this and came the closest to success with this approach, but I think the problem is that I just don't know how to populate that List, as in what the syntax would be to add them. – Keven M Nov 11 '11 at 15:15
  • @KevenM Have you tried `foreach (object o in ccChildren.GetChildren(rvraDockPanel, 2)) list.Add(o as MyClearable);` You also need to make sure all the controls in that dock panel are the descendent types you have created, i.e. `ClearableDigitBox` etc. – James Nov 11 '11 at 15:53
  • Yeah, couldn't get that to work either. But in trying to, I had a thought, and maybe you can verify whether this would work or not (not entirely sure how to implement it if it would). As I pointed out in the second post I made, the only differences between digitbox, phonebox, and datebox is the presence of an `IsFormattingKey` method. Instead of writing those as inherited classes, could I use an interface for those? Because then the foreach loop could **just** refer to one type of custombox instead of 5, right? – Keven M Nov 11 '11 at 16:53
  • If they all inherit from WatermarkTextbox then you don't need an interface, just cast each object to a `WatermarkTextbox` and set its `Text` property to empty. – James Nov 11 '11 at 17:26
0

Aren't all the input boxes a part of Control object?

if so, and you want to clear all the text from the controls then i would probably have a method like:

public void ClearText(List<Control> items)
    {
        foreach (Control control in items)
        {
            control.Text = string.Empty;
        }
    }

if you just want to locate controls of a specific type

public void ClearText(List<Control> items)
        {
            foreach (Control control in items)
            {
                if (control is TextBox)
                    ((TextBox)control).Text = string.Empty;
                else if (control is DigitBox)
                    ((DigitBox)control).Text = string.Empty;
                else
                { // Handle anything else.}
            }
        }
Jonathan
  • 9
  • 2
0

In response to a couple of the replies so far, this is the class file I have for the custom boxes. The NumberTextBox class is the default snippet that VS added. I haven't used it, just haven't deleted it either. In addition to the DateBox(which is collapsed to save space) class, there is also a PhoneBox class that inherits from DigitBox as well. the WatermarkTextBox class that DigitBox inherits from is in the WpfToolkit.Extended.dll. The only real difference in these classes is that each adds a method to allow/disallow formatting keys being pressed (parenthesis, periods, hyphens, etc).

This class basically came about as a result of trying to merge several different snippets I found around the web, but the purpose of these boxes is to enable a watermark and also restrict the characters that can be entered into those boxes.

public class NumberTextBox : Control
{
    static NumberTextBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(NumberTextBox), new FrameworkPropertyMetadata(typeof(NumberTextBox)));
    }

}    

public class DigitBox : WatermarkTextBox, IClearable
{
    #region Constructors
    ///<summary>
    ///The default constructor
    /// </summary>
    public DigitBox()
    {
        TextChanged += new TextChangedEventHandler(OnTextChanged);
        KeyDown += new KeyEventHandler(OnKeyDown);
        PreviewKeyDown += new KeyEventHandler(OnPreviewDown);
    }
    #endregion

    #region Properties
    new public String Text
    {
        get { return base.Text; }
        set
        {
            base.Text = LeaveOnlyNumbers(value);
        }
    }
    #endregion

    #region Functions
    public bool IsNumberKey(Key inKey)
    {
        if (inKey < Key.D0 || inKey > Key.D9)
        {
            if (inKey < Key.NumPad0 || inKey > Key.NumPad9)
            {
                return false;
            }
        }
        return true;
    }

    public bool IsActionKey(Key inKey)
    {
        return inKey == Key.Delete || inKey == Key.Back || inKey == Key.Tab || inKey == Key.Return;
    }

    public string LeaveOnlyNumbers(String inString)
    {
        String tmp = inString;
        foreach (char c in inString.ToCharArray())
        {
            if (!IsDigit(c))
            {
                tmp = tmp.Replace(c.ToString(), "");
            }
        }
        return tmp;
    }

    public bool IsSpaceKey(Key inKey)
    {
        if (inKey == Key.Space)
        {
            return true;
        }
        return false;
    }

    public bool IsDigit(char c)
    {
        return (c >= '0' || c <='9');
    }
    #endregion

    #region Event Functions
    protected virtual void OnKeyDown(object sender, KeyEventArgs e)
    {
        e.Handled = !IsNumberKey(e.Key) && !IsActionKey(e.Key) && !IsSpaceKey(e.Key);
    }

    protected virtual void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        base.Text = LeaveOnlyNumbers(Text);
    }

    protected virtual void OnPreviewDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Space)
        {
            e.Handled = true;
        }
    }
    #endregion
}


public class DateBox : DigitBox
Keven M
  • 972
  • 17
  • 47