This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How can I invoke an event handler from a function?
I need to do something I was pretty sure should be simple, I have Form with controls and every control have event handler that sets label with correct formating etc.
What I need is to call every handlers collection for every control on specific type.
I browsed all stackoverflow and never saw result.
It is simple application so please stop comments like: "you need additional function called from event handler".
This is what I tried
foreach (Control ctrl in Controls)
{
if (ctrl is TrackBar)
{
TrackBar tb = ctrl as TrackBar;
Invoke(tb.Scroll, tb, new EventArgs());
}
}
But I see very strange error
The event 'System.Windows.Forms.TrackBar.Scroll' can only appear on the left hand side of += or -=
Any solution?
You can't raise event outside class in which event is declared (only adding and removing handlers is available). Instead of trying to raise event, which will call event handler, simply extract handler logic to separate method, and call that method:
foreach (TrackBar tb in Controls.OfType<TrackBar>())
{
DoSomething(tb.Value);
}
And handler:
void trackBar_Scroll(object sender, EventArgs e)
{
DoSomething(((TrackBar)sender).Value);
}
Error appears because tb.Scroll is event not delegate.
You could try making a delegate with the same Signature as the Event, create a common eventhandler for your controls and then you can either invoke it or respond to the event as normal.
i.e.
Something like this:
public partial class Form1 : Form
{
public delegate void trackbarscroll( object sender, EventArgs e);
trackbarscroll tbs;
public Form1()
{
InitializeComponent();
trackBar1.Scroll += new EventHandler(trackBar_Scroll);
trackBar2.Scroll += new EventHandler(trackBar_Scroll);
tbs = trackBar_Scroll;
}
void trackBar_Scroll(object sender, EventArgs e)
{
TrackBar tb = (TrackBar)sender;
}
private void button1_Click(object sender, EventArgs e)
{
foreach (Control ctrl in Controls)
{
if (ctrl is TrackBar)
{
TrackBar tb = ctrl as TrackBar;
Invoke(tbs,tb, new EventArgs());
}
}
}
}
Related
This question already has answers here:
Handling a Click for all controls on a Form
(2 answers)
Closed 6 years ago.
I am designing a small application in which I open a new form with some controls. I want to close this form if idle for some time. Let say the form is having many buttons, scroll bars, picture box....if none of them is clicked (within 10 seconds) the form should close.
I have used a timer of 10 seconds , i want to reset it if any of the control is pressed. I can do it individually but would become very cumbersome doing it for all the controls. Can i do it by some simpler way....I read on net:
foreach (Control cc in Controls)
but didn't knew how to use it. Please help.
This should get you started
private void Form1_Load(object sender, EventArgs e)
{
foreach(Control control in this.Controls)
{
control.Click += Oncontrol_Click;
}
}
private void Oncontrol_Click(object sender, EventArgs e)
{
Control control = sender as Control;
MessageBox.Show($"{control.Text} is clicked");
}
You can bind the click event to all the controls inside the foreach loop.
foreach (Control c in Controls)
{
c.Click += (o, args) => ResetTimer();
}
Now each time a user clicks a control, ResetTimer() gets fired.
You need to do this to add the click event to all of the controls on a form:
private void Form1_Load(object sender, EventArgs e)
{
AttachHandler(this, (s, e2) => ResetTimer());
}
private void AttachHandler(Control control, EventHandler handler)
{
control.Click += handler;
foreach (Control c in control.Controls)
{
AttachHandler(c, handler);
}
}
It needs to recursively go down all controls that can contain other controls.
I have a form with many labels and text boxes. I'd like to have the title highlighted red if any of the fields are modified. Is there an easy way to do this or do you need to add the event callback to each form object individually? Thanks!
Off the top of my head you could do something like this in the form load event to add the events...
foreach (var control in this.Controls)
{
if (control is Label)
{
((Label)control).TextChanged += Controls_TextChanged;
}
else if (control is TextBox)
{
((TextBox)control).TextChanged += Controls_TextChanged;
}
}
When you're looking at the events associated with each control, you notice that you can 'drop down' a list of all events coded in the form. If you double click on a 'Text Changed' event, for example, it will be controlname_textchanged(...). However, if you have a generic handler for all, then you could call it textchangedevent(...). The generic event handler will need to have the sender and event object associated with that event in the parameters.
If you're doing this in a user control and have to update the main form, then you will bubble this up through a public event eventobject youreventname, and bind that event on the main form.
Something like this should work:
foreach (System.Windows.Forms.Control cont in this.Controls)
cont.Validating += new System.Windows.Forms.ValidationEventHandler(this.Control_Validating_Method)
Then you could test for the control type in the event code and compare the value with the original value.
Yes you can easily add controls to the same event. This example puts the 'Labels' and 'Textboxes' in the same event.
private void Form1_Load(object sender, EventArgs e)
{
foreach (Control x in this.Controls)
{
if(x is Label)
((Label)x).MouseHover+=new EventHandler(AllLabels_HoverEvent);
else if(x is TextBox)
((TextBox)x).MouseHover+=new EventHandler(AllTextboxes_HoverEvent);
}
}
void AllLabels_HoverEvent(object sender, EventArgs e)
{
Label label = (Label)sender;
// label.dowhateveryouwant...
}
void AllTextboxes_HoverEvent(object sender, EventArgs e)
{
Textbox textbox = (Textbox)sender;
// textbox.dowhateveryouwant...
}
If you need any more clarification please comment below and I will add on to my answer or modify it to suite any particular needs you have. Be careful though if you have controls nested in other containers they won't be in this.Controls.
Exactly where I must write this code?
button1.MouseHover += Common_MouseHover;
The problem is I want to declare one event handler and point each button at it. This is the common handler:
private void Common_MouseHover(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null)
btn.Image = pic
}
But I dont know where i must write:
button1.MouseHover += Common_MouseHover;
utton2.MouseHover += Common_MouseHover;
.. etc
In designer? Where exactly?
Either in the designer or the Constructor of your Form or if you are creating dynamic Buttons at the time of creation.
public Form1()
{
InitializeComponent();
button1.MouseHover += new EventHandler(Common_MouseHover);
button2.MouseHover += new EventHandler(Common_MouseHover);
}
If in the Property Editor.
Technically, it depends when you want to assign it. For example, you might not want the event to be handled by that method until certain conditions are met: then you assign the event handler once the conditions are true.
Bear in mind that assigning event handlers can cause memory leaks if you aren't careful. For example, you might have a timer that continually assigns the same event handler to the event. You need to check if the event already has the event handler, or if it's null, or whatever you need to prevent duplication. You might also want to remove event handlers dynamically using the -= operator.
For the example given, the form's constructor seems right, and is the most common place for assigning event handlers manually.
Call following function in your form Constructor after InitializeComponent(); -
private void init()
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
(ctrl as Button).MouseHover += new EventHandler(Common_MouseHover);
}
}
}
Call it like this -
// Form Constructor
public Form3()
{
InitializeComponent();
Init();
}
For my current project I am adding an variable amount of usercontrols : ucTask to my flowlayoutpanel : flpTasks
foreach (task t in tasks)
{
ucTask uct = new ucTask();
uct.id = t.task_id;
uct.date= t.date.ToString();
uct.btnNaam = t.task_id.ToString();
uct.OnButtonclick += new EventHandler(uct_OnButtonclick);
flpTasks.Controls.Add(uct);
}
Now I will have a couple of those usercontrols in the flowlayoutpanel, and I want to fire an event when I press that button. With the EventHandler I can fire an event, but I need to fire a different event for a different button.
void uco_OnButtonclick(object sender, EventArgs e)
{
lblStatus.Text = "TEST";
}
I don't know how to know which button (or usercontrol) I pressed. And I'm out of ideas, any suggestions?
Thanks,
Thomas
Sender of event is actually one of buttons. When you cast sender to Button type, you can access any of Buttons properties and determine which button was pressed:
void uco_OnButtonclick(object sender, EventArgs e)
{
Button button = sender as Button;
if (button == null)
return;
lblStatus.Text = button.Name;
}
UPDATE: after reading your question once again, I get that ucTask is actually UserControl, which rises event when button inside it was clicked.
So, first is naming. Good style for class names in c# is PascalCase. E.g. for task user control good name will be TaskControl. Next goes event naming. It's common to name events as EventName(-ing, -ed). If you want to raise event, then good style is protected method OnEventName(-int, -ed). And another remark - when you writing user controls, you are free to use business terms to name your events. E.g. TaskCreated, TaskChanged. And you also can pass any parameters to your event by creating custom EventArgs.
So, for your user control:
public class TaskChangedEventArgs : EventArgs
{
public TaskChangedEventArgs(int taskId)
{
TaskId = taskId;
}
public int TaskId { get; private set; }
}
public class TaskControl : UserControl
{
public event EventHandler<TaskChangedEventArgs> TaskChanged;
// raise it inside button click event handler
protected void OnTaskChanged(int taskId)
{
if (TaskChanged != null)
TaskChanged(this, new TaskChangedEventArgs(taskId));
}
}
When you use your user control, just subscribe to its TaskChanged event:
uct.TaskChanged += new EventHandler<TaskChangedEventArgs>(uct_TaskChanged);
And all parameters, that you passed via event argument will be available in that event handler:
void uco_TaskChanged(object sender, TaskChangedEventArgs e)
{
lblStatus.Text = e.TaskId.ToString();
}
Well, the sender should be the user control right? Then you can cast and determine the item through ucTask.id.
void uco_OnButtonclick(object sender, EventArgs e)
{
ucTask uc = sender as ucTask;
lblStatus.Text = uc.id.ToString();
}
This presumes that the OnButtonclick event of the user control sends a reference to the user control and not a reference to the pressed button as the sender of the event.
I've built a custom component that basically has a picture box and label in it. In the parent form, I want to be able to detect when its been clicked on. The standard .click event doesn't seem to be working, but I've never used events before so am unsure if I'm using them correctly. Heres the code I'm using (in the parent) to try and make it recognise the click:
Item aItem = new Item();
aItem.Icon = ItemImage;
aItem.Title = Title;
aItem.Click += new EventHandler(ItemClicked);
aItem.Filename = File;
and heres the method its calling:
public void ItemClicked(Object sender, EventArgs e)
{
MessageBox.Show("Item Clicked!");
}
This code never fires. Do I need to put anything into the component or am I just doing this wrong?
Cheers
Right I finally worked it out. Tejs response just confused me more so here's what I did.
In my UserControl I had the following event:
public event EventHandler Clicked;
Then I had an event for when the image was clicked (still in the UserControl) and I just called the Clicked event:
private void imgItem_Click(object sender, EventArgs e)
{
Clicked(this, e);
}
Then in my parent form, when I created the object, I had the following:
Item aItem = new Item();
aItem.Clicked += new EventHandler(ItemClicked);
void ItemClicked(object sender, EventArgs e)
{
MessageBox.Show("Clicked!");
}
You would do this by exposing an event':
Your custom component:
// A custom delegate like MyItemClickedHandler, or you could make a Func<> or Action<>
public event MyItemClickedHandler ItemClickedEvent;
public void ItemClicked(object sender, EventArgs e)
{
if(ItemClickedEvent != null)
ItemClickedEvent(); // Your delegate could pass parameters if needed
}
Then your parent form simply observes the event:
myCustomControl.ItemClickedEvent += new MyItemClickedHandler(SomeMethod);
Then, whenever the event is raised on your custom control, the parent is notified because it subscribed the event.