0

I want when the project is starting to create a custom event for every click event inside my textbox. Then when a new textbox will be created, automatically use this click event. I don't want to create a custom control for this. I want to assign it once from a method.

Or if it is possible to create a default constructor for all my elements without creating a custom control. For example, I don't want to create this. Cause I need to replace all my controls

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace DXApplication1
{
    [ToolboxItem(true)]
    public class Class1 : TextBox
    {
        public Class1()
        {
            this.Click += Class1_Click;
        }

        private void Class1_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Click Event");
        }
    }
}

I have 1000 textboxes on my project. I don't want to add in each onclick method Is there any way to add a click event to all my textboxes in the project? I want to add just one line of code to the program. cs. Is it possible?

hamidie
  • 67
  • 6
dbsoft
  • 31
  • 5
  • 2
    This is totally X-y. What are you trying to do, actually? – Fildor Feb 11 '23 at 10:04
  • 1
    Override [OnClick](https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.onclick?view=netframework-4.8#examples) method. – Alexander Petrov Feb 11 '23 at 10:26
  • @AlexanderPetrov - The OP doesn't want to use inheritance. – Enigmativity Feb 11 '23 at 10:41
  • I'd suggest you look into [Harmony](https://stackoverflow.com/questions/7299097/dynamically-replace-the-contents-of-a-c-sharp-method) to try and patch the TextBox constructor. I wasn't able to get it working though, my program just hangs there, that's why I'm not posting this as an answer. – Frank Z. Feb 11 '23 at 10:43

3 Answers3

3

I'd suggest that you simple traverse all of the controls on your form after you have placed them and then attach the event.

Try something like this:

IEnumerable<TextBox> AllTextBoxes(ScrollableControl @this)
{
    foreach (Control control in @this.Controls)
    {
        if (control is ScrollableControl sc)
        {
            foreach (TextBox tb1 in AllTextBoxes(sc))
            {
                yield return tb1;
            }
        }
        if (control is TextBox tb2)
        {
            yield return tb2;
        }
    }
}
foreach (var tb in AllTextBoxes(this))
{
    tb.Click += (_, _) => MessageBox.Show("Hello");
}
Fildor
  • 14,510
  • 4
  • 35
  • 67
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • Something tells me, op is creating components dynamically ... spidey senses tingle. – Fildor Feb 11 '23 at 10:16
  • 1
    @Fildor - Then there should be a single factory method/delegate that could attach the event. It's effectively a one-liner too. – Enigmativity Feb 11 '23 at 10:17
  • I agree. I just feel the question should be clearer about all that. No criticism to your answer. +1ed it. – Fildor Feb 11 '23 at 10:19
1

If you derive your control from an existing control you can override the OnClick method instead of subscribing to the event.

public class TextBoxEx: TextBox
{
    public TextBoxEx()
    {
    }

    protected override void OnClick(EventArgs e)
    {
        Console.WriteLine("Click Event");
        base.OnClick(e);
    }
}

Then you can replace the type TextBox by TextBoxEx (with find/replace) in the form's .designer.cs file without having to delete and re-insert your textboxes.

Once you have compiled this code, the new textbox appears in the Toolbox window and you can drag and drop it to your form, just as with the standard textbox.


If you have a textBox1_Click method in your form, you can select this same method as event handler for all your textboxes in the properties window: How to: Connect Multiple Events to a Single Event Handler in Windows Forms

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
1

As I understand it, you have three requirements:

  • When the project starts, attach a click event to all TextBox instances already created in the Form designer.
  • When a new text box is created (programmatically or by user interaction) attach the click event to the new textbox automatically.
  • Implement this functionality without making a custom class.

This answer shows one way to meet these three objectives.


Utility

First, make a utility that can iterate all of the controls in the Form, but also all the controls of its child controls.

void IterateControlTree(Action<Control> action, Control control = null)
{
    if (control == null)
    {
        control = this;
    }
    action(control);
    foreach (Control child in control.Controls)
    {
        IterateControlTree(action, child);
    }
}

Attach handler to all existing TextBox controls

Using this utility, initialize any textboxes added in design mode to route to the click handler.

design-time-click

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();

        IterateControlTree((control) =>
        {
            // Attach click handlers to the textboxes
            // already added in the Forms designer.
            if (control is TextBoxBase) 
            {
                control.Click += onAnyClickTextBox;
            }
        });
        .
        .
        .
    }

    // Show the name of the clicked text box.
    private void onAnyClickTextBox(object sender, EventArgs e)
    {
        if(sender is Control control)
        {
            textBox1.Text = $"Clicked: {control.Name}";
        }
    }
}

Attach handler automatically to new TextBox controls

Iterate a second time to attach the ControlAdded event to every control. This way, new TextBox instances can be detected in order to attach the Click event.

runtime click

public MainForm()
{
    .
    .
    .
    IterateControlTree((control) =>
    {
        control.ControlAdded += (sender, e) =>
        { 
            // Get notified when any control collection is changed.
            if(e.Control is TextBoxBase textbox)
            {
                textbox.Click += onAnyClickTextBox;
            }
        };
    });
}

Testing

// FOR TESTING PURPOSES
int _id = 1;
private void onClickNew(object sender, EventArgs e)
{
    flowLayoutPanel.Controls.Add(new TextBox
    {
        Name = $"dynamicTextBox{_id}",
        PlaceholderText = $"TextBox{_id}",
    });
    _id++;
}
IVSoftware
  • 5,732
  • 2
  • 12
  • 23