27

I have a UserControl which contains 3 labels. I want to add an event for it, which occurs when the text of one of the labels changed.
I am using Visual Studio 2010

shA.t
  • 16,580
  • 5
  • 54
  • 111
Saeed
  • 7,262
  • 14
  • 43
  • 63

6 Answers6

55

First, you need to declare the event within your class (alongside your methods and constructors):

public event EventHandler LabelsTextChanged;

Then you need to create a method to handle the individual labels' TextChanged events.

private void HandleLabelTextChanged(object sender, EventArgs e)
{
    // we'll explain this in a minute
    this.OnLabelsTextChanged(EventArgs.Empty);
}

Somewhere, probably in your control's constructor, you need to subscribe to the label's TextChanged events.

myLabel1.TextChanged += this.HandleLabelTextChanged;
myLabel2.TextChanged += this.HandleLabelTextChanged;
myLabel3.TextChanged += this.HandleLabelTextChanged;

Now for the HandleLabelsTextChanged method. We could raise LabelsTextChanged directly; however, the .NET framework design guidelines say that is it a best practice to create an OnEventName protected virtual method to raise the event for us. That way, inheriting classes can "handle" the event by overriding the OnEventName method, which turns out to have a little better performance than subscribing to the event. Even if you think you will never override the OnEventName method, it is a good idea to get in the habit of doing it anyway, as it simplifies the event raising process.

Here's our OnLabelsTextChanged:

protected virtual void OnLabelsTextChanged(EventArgs e)
{
    EventHandler handler = this.LabelsTextChanged;
    if (handler != null)
    {
        handler(this, e);
    }
}

We have to check for null because an event without subscribers is null. If we attempted to raise a null event, we would get a NullReferenceException. Note that we copy the event's EventHandler to a local variable before checking it for null and raising the event. If we had instead done it like this:

if (this.LabelsTextChanged != null)
{
    this.LabelsTextChanged(this, e);
}

We would have a race condition between the nullity check and the event raising. If it just so happened that the subscribers to the event unsubscribed themselves just before we raised the event but after we checked for null, an exception would be thrown. You won't normally encounter this issue, but it is best to get in the habit of writing it the safe way.

Edit: Here is how the public event EventHandler LabelsTextChanged; line should be placed:

namespace YourNamespace
{
    class MyUserControl : UserControl
    {
        // it needs to be here:
        public event EventHandler LabelsTextChanged;

        ...
    }
}

Here are the framework design guidelines on event design for further reading.

Zach Johnson
  • 23,678
  • 6
  • 69
  • 86
  • Your Idea also has the same problem, the compiler says:
    "Expected class, delegate, enum, interface, or struct"
    on the first line it has a problem with event
    – Saeed Aug 15 '10 at 06:38
  • 2
    @saeed: Where are you putting `public event EventHandler LabelsTextChanged;`? It has to be *inside* your class (not inside a method or outside the class definition). – Zach Johnson Aug 15 '10 at 06:40
  • @ZachJohnson Very helpful! Is the "this" keyword needed for the inheriting stuff, or is it optional in this case? – FlyerDragon Oct 19 '15 at 15:04
  • 2
    You can shorten your check for null `this.ElementChanged?.Invoke(this, e);` – Michał Woliński Jun 07 '18 at 08:46
3

First you should declare an event in your usercontrol for example:

public event EventHandler TextOfLabelChanged;

then you have to call the call back function that is bound to your event(if there's any) in runtime.You can do this by handling the TextChanged event of a label like this:

public void LabelTextChanged(object sender,EventArgs e)
{
if(TextOfLabelChanged!=null)
TextOfLabelChanged(sender,e);
}

You can have your own EventArgs object if you like.

somewhere in your code you should bound your label TextChanged event to this method like this:

_myLabel.TextChanged+=LabelTextChanged;
Beatles1692
  • 5,214
  • 34
  • 65
1

There is a very simple way to do that!

On the UserControl Form :

  1. change properties to public to access everywhere

on the main form , where you are using UserControl:

.5: in the using region add using userControl1=UserControl.userControl1

1.Add 'Laod' event to your UserControl :

this.userControl1.Load += new System.EventHandler(this.userControl1_Load);

2.In the userControl1_Load :

private void userControl1_Load(object sender, EventArgs e)
{
     (sender as UserControl1).label1.TextChanged += label1_TextChanged; 
     //add a 'TextChanged' event to the label1 of UserControl1 
     OR use direct cast:
     ((UserControl1) sender).label1.TextChanged += label1_TextChanged;

}

3.In th label1_TextChanged:

 private void label1_TextChanged(object sender, EventArgs e)
 {
     //do whatever you want
 }
Arsalan
  • 709
  • 2
  • 14
  • 27
1
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;

// ...

protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
    if (LabelTextChanged != null) {
        LabelTextChanged(this, e);
    }
}
thelost
  • 6,638
  • 4
  • 28
  • 44
  • It has a compile errror, wihch says: "Expected class, delegate, enum, interface, or struct" on the second line it seems to have a problem with "event" – Saeed Aug 15 '10 at 06:30
1

compile error, which says: "Expected class, delegate, enum, interface, or struct" on the second line it seems to have a problem with "event...


These 2 lines need to be INSIDE the class declaration.

public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;
Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
Vince
  • 11
  • 1
0

You must be declaring the event and delegate within the Namespace. Try to bring the code within the class Scope. It will run fine.

akjoshi
  • 15,374
  • 13
  • 103
  • 121
prem
  • 1