views:

45

answers:

5

I'm trying to mimic the web fuctionality of having a label over a textbox that shows the type of value the textbox should contain. I can add the events individually but I'm wondering if there is a way to add 'Behavior' to a set of controls.

Please see example code:

private void labelFirstName_Click(object sender, EventArgs e)
{
    HideLabelFocusTextBox(labelFirstName, textBoxFirstName);
}

private void HideLabelFocusTextBox(Label LabelToHide, TextBox TextBoxToShow)
{
    LabelToHide.Visible = false;
    TextBoxToShow.Focus();
}

private void textBoxFirstName_Leave(object sender, EventArgs e)
{
    if (String.IsNullOrEmpty(textBoxFirstName.Text))
        labelFirstName.Visible = true;
}

private void textBoxFirstName_Enter(object sender, EventArgs e)
{
    labelFirstName.Visible = false;
}
+1  A: 

You could always create a user control that does this. Put both the TextBox and the Label inside the control and code up the logic inside the user control. That way every instance of that control will behave the same.

ErikHeemskerk
I thought about this but I don't want to worry about the control size and functionality
Chris
+2  A: 

You could subclass the text box control (write your own that inherits a textbox)

Btw, i have thought about this and i would take another approach:

i would override the text box's paint handler and when the textbox contains no information, draw an info string into it.

Something like:

using System;
using System.Windows.Forms;
using System.Drawing;

class MyTextBox : TextBox
{
    public MyTextBox()
    {
        SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        if (string.IsNullOrEmpty(this.Text))
        {
            e.Graphics.DrawString("My info string...", this.Font, System.Drawing.Brushes.Gray, new System.Drawing.PointF(0, 0));
        }
        else
        {
            e.Graphics.DrawString(Text, this.Font, new SolidBrush(this.ForeColor) , new System.Drawing.PointF(0, 0));
        }
    }

    protected override void OnTextChanged(EventArgs e)
    {
        Invalidate();
        base.OnTextChanged(e);
    }
}
Paul Sasik
do you just programatically add a label to the textbox in the class? If so, how can you map it to the textbox's font size and type.
Chris
@Chris: That's correct. You do it programmatically. You can query the text box's public properties and assign them directly to any other for example: MyLabel.Font = MyTextBox.Font;
Paul Sasik
@Chris: Check out the new code sample. It's simple and just a bit quirky but demonstrates the idea.
Paul Sasik
The drawing quirk i mentioned is mitigated by setting the font on the control to Microsoft Sans Serif, 10pt, Bold... lol. It's 2010... GDI+ has been around for a while now and the old Win32 crud is still bubbling up to the surface! (Running VS 2010 with .NET 4.0...)
Paul Sasik
Man, so many good answers. I like this one because of it's simplicity and weight (it's pretty light). It's a little clunky but that can be worked out.
Chris
+1  A: 

Tie Behaviour

You can tie the feature/behaviour closer to the TextBox control by using extension methods. This simple solution might make it feel more tightly knit:

// NOTE: first parameter "this TextBox thisText"- these are all extension methods.

static public void AssignLabel(this TextBox thisText, Label companionLabel) {
    thisText.Tag = companionLabel;

    // HOOK UP EVENT AT THIS POINT, WHEN LABEL IS ASSIGNED (.NET 3.x)
    thisText.Leave += (Object sender, EventArgs e) => {
        LeaveMe(thisText); // Invoke method below.
    };
}

static public void FocusText(this TextBox thisText) {
    if (! ReferenceEquals(null, thisText.Tag))
        (Label)thisText.Tag).Visible = false;
    thisText.Focus();
}

static public void LeaveMe(this TextBox thisText) {
    if (String.IsNullOrEmpty(thisText.Text))
        ((Label)thisText.Tag).Visible = true;
}

//etc.

and then use your textbox instances like so:

Label overlay1 = new Label();  // Place these appropriately
Label overlay2 = new Label();  // on top of the text boxes. 
Label overlay3 = new Label();  
TextBox myTextbox1 = new TextBox();
TextBox myTextbox2 = new TextBox();
TextBox myTextbox3 = new TextBox();

// Note: Calling our extension methods directly on the textboxes.
myTextbox1.AssignLabel(overlay1);
myTextbox1.FocusText();
myTextbox1.LeaveMe();

myTextbox2.AssignLabel(overlay2);
myTextbox2.FocusText();
myTextbox2.LeaveMe();

myTextbox3.AssignLabel(overlay3);
myTextbox3.FocusText();
myTextbox3.LeaveMe();
//etc...

How it Works

The code is cleaner and applies to all TextBoxes you instantiate.

It relies on the the .Tag property of the TextBox class to store a Label reference into (so each TextBox knows its label), and also extension methods introduced with .NET 3.x which allow us to "attach" methods onto the TextBox class itself to tie your behaviour directly to it.

I took your code and produced almost the same thing with tweaks to turn it into extension methods, and to associate a Label with your Textbox.

Variation

If you want to attach the same method to other controls (and not just the text box) then extend the base Control class itself like:

static public void LeaveMe(this Control thisControl) { //...
John K
I suppose this only works with controls created at runtime? I followed the example using controls on the design surface with no build errors, but none of the events work on the controls.
Chris
The extension methods will extend all controls of that Type (in this case TextBox class) no matter if they were created on the design surface or instantiated by yourself. Methods don't show up at design time although properties do. (Oh .... just realized you said EVENTS! ...gotta' look into that...)
John K
Okay ... added EVENT into sample code so it will be hooked up automatically whenever the `AssignLabel(..)` extension method is used.
John K
I almost picked yours, I like it so much and you are a great documenter.
Chris
could you edit your post somehow so I can up vote it, stackoverflow's ultra-micromanagement ui just caused me to steal a point I gave you
Chris
Just gave it an edit, thanks.
John K
There's no ONE answer to this question, this answer is the best written and derserves some special credit
Chris
+1  A: 

Another option might be to use an Extender Provider. These basically let you add a behavior to any control (though these can be limited if I remember right) at design time. The ToolTip is an example of an Extender Provider that is already floating around in the framework. I used these quite a bit once upon a time to do things like add support for getting the text values of controls from a resource file.

ckramer
+1  A: 

I would subclass the regular textbox and add properties which allow you to either find the associated label or set a reference to the associated label directly.

Typically in winform projects, I subclass all controls before adding them to my forms, so I can add common functionality very easily without having to change forms in the future.

Cade Roux