3
votes

I am learning about event handlers and delegates. I have a single form with 4 text boxes and a list box. I'd like to have a delegate that listens for text box changes to ANY of the 4 boxes. The method associated with the delegate would simply be a method that takes the text value of the text box that changed, and add that as a new list item. My question is how to write the delegate to listen to all of the text boxes, and when I call the function to add the list box item, how can I pass in the text box object since I won't know explicitly which one raised the event? Will this be contained in the EventArgs e?

Rather than use multiple event handlers:

this.textBo1.TextChanged += txt_TextChanged;
this.textBo2.TextChanged += txt_TextChanged;
this.textBo3.TextChanged += txt_TextChanged;
this.textBo4.TextChanged += txt_TextChanged;

I'd like something like:

public delegate ListenToTextBoxes(object sender, EventArgs e);

Maybe that doesn't make sense since I'm new to delegates, but it seems reasonable to me that I should be able to make one delegate listen to text box controls in general, and then when it raises the event I cast the object sender and get the text box text. But how do I create the delegate so it listens ONLY to text boxes, or other types of controls?

3

3 Answers

5
votes

What about something like this ?

// form constructor
public MyForm()
{
   InitializeComponent();
   this.textBo1.TextChanged += txt_TextChanged;
   this.textBo2.TextChanged += txt_TextChanged;
   this.textBo3.TextChanged += txt_TextChanged;
   this.textBo4.TextChanged += txt_TextChanged;
}

// event handler
void txt_TextChanged(object sender, EventArgs e)
{
   var textBox = (TextBox)sender;
   this.myList.Add(textBox.Text);
}

EDIT :
(according to the question update)

Actually, the previous code can easily modified to created one single delegate and pass it to all the textboxes, but it doesn't change too much (there're still four event subscriptions):

public MyForm()
{
    InitializeComponent();

    // EventHandler is defined as:
    // delegate void EventHandler(object sender, EventArgs e)
    // so its signature is equal to your delegate:
    // delegate void ListenToTextBoxes(object sender, EventArgs e);
    // Hence, if you receive that delegate from somewhere out, you can pass it
    // to TextChange events
    var myDelegate = new EventHandler(txt_TextChanged);

    this.textBox1.TextChanged += myDelegate;
    this.textBox2.TextChanged += myDelegate;
    this.textBox3.TextChanged += myDelegate;
    this.textBox4.TextChanged += myDelegate;
}

The problem is that you do need to subscribe the TextChanged event for each TextBox control, there's no magic way to say "register all the TextBox.TextChange events to this delegate".
But, if you are sure that all the textboxes that you want to register are children of this control, you can use a loop, e.g. :

public MyForm()
{
    InitializeComponent();
    var myDelegate = new EventHandler(txt_TextChanged);
    foreach (var ctrl in this.Controls)
    {
        var txtBox = ctrl as TextBox;
        if (txtBox != null)
            txtBox.TextChanged += myDelegate;
    }
}
1
votes

Use "sender". Here's an example:

textBox1.Click += AllTextBoxes_Click;
textBox2.Click += AllTextBoxes_Click;

void AllTextBoxes_Click(object sender, EventArgs e)
{
    TextBox tb = sender as TextBox;
    tb.Text = "Clicked here";
}

Due to updated question:

public Form1()
{
    InitializeComponent();
    Listen(this);
}    

void Listen(Control ctrl)
{
    foreach (Control ctrl2 in ctrl.Controls)
    {
        if (ctrl2 is TextBox) (ctrl2 as TextBox).TextChanged += tb_TextChanged;
        foreach (Control ctrl3 in ctrl2.Controls) Listen(ctrl3);
    }
}

void tb_TextChanged(object sender, EventArgs e)
{
    //Do things...
}
0
votes

You might intuit the other answers that sender is the object raising the event (one of your four text boxes once the event is attached to Click), however for an in depth explanation of determining the sender I'd suggest HOW TO: Determine the Sender of an Event Without Using the Control.Name Property