Is it possible to override click event for all my textboxs? - c#

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?

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");
}

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

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.
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.
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++;
}

Related

Is there a way to activate a Button that exists within another class?

I am using C# and Xamarin. I have two separate classes. One class is essentially the user interface and another class is acting as a custom built generic entry for users to input data and search for results by clicking a button.
Main UI Class:
Class MainPage
{
public MainPage
{
Content = new StackLayout
{
Children =
{
new InputClass // This is my custom built user entry class
{
}.Invoke(ic => ic.Clicked += WhenButtonPressedMethod) // The problem is here, I can't figure out how to call the button within the input class to fire a clicked event.
}
}
}
}
public async void WhenButtonPressedMethod (object sender, EventArgs e)
{
// Supposed to do stuff when the button is pressed
}
InputClass:
public class InputClass : Grid
{
public delegate void OnClickedHandler(object sender, EventArgs e);
public event OnClickHandler Clicked;
public InputClass
{
Children.Add(
new Button {}
.Invoke(button => button.Clicked += Button_Clicked)
)
}
private void Button_Clicked(object sender, EventArgs e)
{
Clicked?.Invoke(this, e);
}
}
The "InputClass" is a grid that holds a title text label, an entry and a button that a user can press to submit and search data. The button in this class is what I'm trying to actually access to invoke/cause a click event so that the method in the main UI class can be called. But, when I try to invoke a click event on the "InputClass" I can't access the button inside of it, I can only access "InputClass" itself which is just a grid with no useful event properties.
Any solutions or ideas?
If you are running into the same problem as mentioned here, follow the code on this page and read through the comments, it covers enough to be able to piece it together. My mistake was attaching Invokes to the wrong objects.
Don't know why fluent Invoke didn't work correctly.
Add the event handlers this way:
public MainPage
{
var ic = new InputClass();
ic.Clicked += WhenButtonPressedMethod;
Content = new StackLayout
{
Children = { ic }
}
}
public InputClass
{
var button = new Button;
button.Clicked += Button_Clicked;
Children.Add(button);
}

RichTextBox blocks DragDrop event

I have DragDrop and DragEnter events on my SplitContainer.Panel:
splitContainer.Panel.DragDrop += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragDrop);
splitContainer.Panel.DragEnter += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragEnter);
It works perfect with every control inside SplitContainer.Panel except RichTextBox controls.
How it looks like:
So DragDrop/DragEnter works perfectly in every control inside SplitContainer except controls which is marked yellow color.
What I tried:
1) Set
RichTextBox.AllowDrop = false;
So I even DragEnter is unavailable with "action is not allowed" cursor.
2) Set
RichTextBox.AllowDrop = true;
After this cursor is ok, but it doesnt work because expects additional DragEventHandler in other case it doesnt work.
3) Set
RichTextBox.EnableAutoDragDrop=false;
RichTextBox.AllowDrop=true;
Same result as 2) variant.
I dont want to set DragDrop/DragEnter event for every RichTextBox inside SplitContainer because inside FlowLayoutPanel they are created dynamically.
The question is: is there any method like e.PreventDefault analog in C#? Or what can I do except setting events for every RichTextBox to make it work?
This worked for me
I created 2 custom controls
Custom SplitControl
public partial class SplitControlCustom : SplitContainer
{
public SplitControlCustom()
{
InitializeComponent();
}
public void ForceDrageDrop(DragEventArgs eventArgs)
{
OnDragDrop(eventArgs);
}
public void ForceDragEnter(DragEventArgs eventArgs)
{
OnDragEnter(eventArgs);
}
}
Custom RichTextBox
public partial class RichTextBoxCustom : RichTextBox
{
public RichTextBoxCustom()
{
InitializeComponent();
this.AllowDrop = true;
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDragEnter(drgevent);
}
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDrageDrop(drgevent);
}
}
}
Please let me know if it worked
I don't see how you can make this work directly. But then, since you are already willing to add a few lines of code while generating the controls, why not add the necessary events via a few lines of Lambda..:
Let's assume you have just created a RichTextBox and are ready to add it to some Controls collection..:
RichTextBox richTextBox = new RichTextBox ();
...
richTextBox.AllowDrop = true;
richTextBox.DragEnter += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragOver += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragDrop += (ss, ee)
=> { splitContainer.Panel_DragDrop(splitContainer.Panel, ee); };
The first two lambdas set the effect to copy without any checks; of course you will want to add those and pick the appropriate effect.
The third lambda passes the DragEventArgs on the the DragDrop event of the containing panel, so now the RTB is actually 'D&D-through' ..
Just create a custom RichTextBox and override it's DragDrop Events.
public class CustomRichTextBox : RichTextBox
{
#region Methods
#region Overrides
protected override void OnDragEnter(DragEventArgs e)
{
// base.OnDragEnter(e);
}
protected override void OnDragOver(DragEventArgs e)
{
// base.OnDragOver(e);
}
protected override void OnDragLeave(DragEventArgs e)
{
// base.OnDragLeave(e);
}
protected override void OnDrop(DragEventArgs e)
{
// base.OnDrop(e);
}
#endregion
#endregion
}
For some reason RichTextBoxes seem to handle all DragDrop events by default.
In WPF the events will propagate till it gets to the control that expects these events. I'm not sure about WinForms though.
This is what resolved this issue for me.
I had these two events defined, which should have been good enough
MyRichTextBox.DragEnter += MyRichTextBox_DragEnter;
MyRichTextBox.DragDrop += MyRichTextBox_DragDrop;
I found that this one is also apparently needed when using a RichTextBox embedded in
certain controls.
MyRichTextBox.DragOver += MyRichTextBox_DragOver;
private void MyRichTextBox_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}

Set StatusLabel text in one form from UserControl

I have a Windows Form (MainForm1) that contains a ToolStrip with a label in it (StatusLabel). MainForm1 also contains a User Control (UserControl1). The User Control contains a button (Button1). When Button1 is clicked it initializes a DataGridView, but that is not important.
When Button1 is clicked in UserControl1, I want to display text in the MainForms StatusLabel.
But I don't know how to do that from one UserControl to the MainForm.
The flow chart describes how I would like it to function.
You can do this simply by creating an event in your User Control
public event EventHandler<string> MessageHasSent;
public void SendMessage(string message)
{
EventHandler<string> ms = MessageHasSent;
if (ms!= null)
{
ms(this,message);
}
}
And in every where in your class that you want Raise this event.In your case you want by clicking on button send message
public Button1_Click( object sender,EventArgs e)
{
SendMessage("YourMessage");
}
And use it like other events.In your MainForm use this event of your UserControl .
public class MainForm:Form
{
public MainForm()
{
UserControl1.MessageHasSent +=SetToolStripLabel;
}
public SetToolStripLabel( object sender,string e)
{
//Set e to Label
}
}

Changing the properties of the active control automatically

Please consider that im a newcomer to c#. After scanning about 700 posts i decided to post one more question:
On my windows form (c#) I have some controls including textboxes, checkboxes and so on.
I want to change the backcolor whenever the controls become active.
I know i could raise 'enter' and 'leave' events for each control to change the corresponding properties but there should be another way.
Simply hook Enter and Leave events - toggling the color in each. Save the last color saved in OnEnter to use in OnLeave
public Form1()
{
InitializeComponent();
var lastColorSaved = Color.Empty;
foreach(Control child in this.Controls)
{
child.Enter += (s, e) =>
{
var control = (Control)s;
lastColorSaved = control.BackColor;
control.BackColor = Color.Red;
};
child.Leave += (s, e) =>
{
((Control)s).BackColor = lastColorSaved;
};
}
}
You customize control classes just like you customize any class, you derive your own class and override the virtual methods. Arbitrarily:
using System;
using System.Drawing;
using System.Windows.Forms;
class MyTextBox : TextBox {
protected override void OnEnter(EventArgs e) {
prevColor = this.BackColor;
this.BackColor = Color.Cornsilk;
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.BackColor = prevColor;
base.OnLeave(e);
}
private Color prevColor;
}
Now any MyTextBox you drop on the form will have this behavior without having to implement events. Although there's certainly nothing wrong with using events.
Create a class (eg. ControlColorizer) and in its constructor pass:
1) The backcolor for the 'active control' and save to a internal Color variable
2) a variable length Control array
In the contructor add the same event handler for OnEnter and OnLeave on each control
In the OnEnter event set the backcolor
In the OnLeave event set the standard background color
The advantage is all in the use of the class:
1) Declare a global instance in your form class
2) Initialize in the form contructor after the InitializeComponent.
3) Forget everything else. No other code required
So let me explain everything with code:
This will go in a file called ControlColorizer.cs
public class ControlColorizer
{
private Color _setBColor = SystemColors.Window;
public ControlColor(Color bkg, params Control[] ctls)
{
_setBColor = bkg;
foreach (Control o in ctls)
{
o.Enter += new EventHandler(o_Enter);
o.Leave += new EventHandler(o_Leave);
}
}
private void o_Enter(object sender, EventArgs e)
{
if (sender is Control)
{
Control c = (Control)sender;
c.BackColor = _setBColor;
}
}
private void o_Leave(object sender, EventArgs e)
{
Control c = sender as Control;
c.BackColor = SystemColors.Window;
}
Now, in every form contructor where you need the functionality you have this
ControlColirizer _ccz;
public Form1()
{
InitializeComponent();
// Create an instance of ControlColorizer, pass the background color
// the list of Controls and that's all
_ccz = new ControlColorizer(Color.LightYellow, this.TextBox1,
this.TextBox2, this.TextBox3, this.TextBox4);
}

how to close window form which is hosting WPF user control from within a WPF user control

I want to close a window form that is hosting a WPF user control. Something like this as used while closing a current form in window application. But for WPF application I am not able to get reference to user controls parent
How to get Form which is hosting this control so that I can close my form
this.Close()
Add to your WpfControl property
public Form FormsWindow { get; set; }
In your WinForm add event handler for ElementHost's event ChildChanged:
using System.Windows.Forms.Integration;
public MyForm() {
InitializeComponent();
elementHost.ChildChanged += ElementHost_ChildChanged;
}
void ElementHost_ChildChanged(object sender, ChildChangedEventArgs e) {
var ctr = (elementHost.Child as UserControl1);
if (ctr != null)
ctr.FormsWindow = this;
}
After that you can use the FormsWindow property of your WpfControl to manipulate window. Example:
this.FormsWindow.Close();
An alternative solution could be,
Window parent = Window.GetWindow(this);
parent.Close();
Just want to add to #The_Smallest's otherwise very clear answer.
If you just copy and past the event handler code, you will still need to set your Forms's ChildChanged event to ElementHost_ChildChanged. I missed that step and spent 30 minutes trying to figure out why FormsWindow was null.
In order to call the Form object of the MyControl class already. We have in it a Form field to which we pass an instance object open Form. Having an assigned object we can freely manipulate it (including also call the function form.Close ();
WPF Control (with XAML):
public class MyControl : UserControl
{
public Form form = null;
public MyControl()
{
InitializeComponent();
this.PreviewKeyDown += new KeyEventHandler(HandleEsc);
}
private void HandleEsc(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
form.Close();
}
}
}
Form:
public class MainForm
{
//...
public Form form = null;
public MainForm(MyControl myControl)
{
InitializeComponent();
//...
myControl.form = (Form)this;
}
}

Categories