Throwing events through objects - c#

I'm developing a Windows Mobile 5.0 or above application with .Net Compact Framework 2.0 SP2 and C#.
I have a Winform (Form1) with a control (Control1) that contains another control (Control2). For example, a winform with a panel and inside this panel there is a button, but in my case Control1 and Control2 are custom controls.
Control2 has an event, Click, that is thrown when the user does click over it. This click event must be handled by Form1. To do it, first I handle the event on Control1 that throws a new event that is handled on Form1. This my code:
On Control1:
public event EventHandler Control2Click;
private void control2_Click(object sender, EventArgs e)
{
if (Control2Click != null)
{
Control2Click(sender, e);
}
}
On Form1:
private void control1_Control2Click(object sender, EventArgs e)
{
// Do something interesting.
}
Is there a better way to handle Control2_Click directly in Form1? I don't know if my way has a bad performance and this kind of events can be handled better.
Thank you!

No, you are doing it right. It is the correct way the bubble an event out of a nested control that isn't directly accessible from a container control. You'd normally use the PerformClick() method to fire the Click event but this doesn't appear to be available in CF.
Perf is not an issue, calling a delegate target is very fast, a dozen nanoseconds or so on a desktop machine. Click is a "human-time" event, anything less than 20 milliseconds is perceived as "instant".

What's stopping you from hooking up the Control2 Click event directly from Form1? Does Control1 expose Control2 via a property? Or perhaps expose an event on Control1 which actually hooks up to the Control2 Click event? For example:
// In Control1
// Assuming Control2 is some sort of Save button, for example
public EventHandler SaveClicked
{
add { control2.Click += value; }
remove { control2.Click -= value; }
}
Note that:
If you change the value of control2 within Control1, the event handlers won't be "transferred" which would be be unfortunate
The sender parameter in the event handler will refer to Control2, not Control1
To be honest I wouldn't expect this to be a performance problem however you handle it - it's just a delegate invocation or two.

Related

Pass click event of button on child control to the parent control [duplicate]

I have a Windows form, having a pane, which contains another class, derived from Windows Forms. This is contained as a control within the pane. It contains two buttons within itself.
I'd like the events of the child control to be passed all the way to the parent window. For example, the child window in the pane has a Cancel button, which is supposed to close it. I'd like the parent control, i.e., the main window to close as well, but how can I intercept the button click event of the child control?
I can modify the child control, but only if there is no other way to achieve this in a proper way, I'd rather like to avoid it.
While you can interact with parent form directly from child like this.ParentForm.Close(), but it's better to raise some events by child control and subscribe for the events in parent form.
Raise event from Child:
public event EventHandler CloseButtonClicked;
protected virtual void OnCloseButtonClicked(EventArgs e)
{
CloseButtonClicked?.Invoke(this, e);
}
private void CloseButton_Click(object sender, EventArgs e)
{
OnCloseButtonClicked(e);
}
Note: To raise the XXXX event, that's enough to invoke the XXXX event delegate; the reason of creating the protected virtual OnXXXX is just to follow the pattern to let the derivers override the method and customize the behavior before/after raising the event.
Subscribe and use event in Parent:
//Subscribe for event using designer or in constructor or form load
this.userControl11.CloseButtonClicked += userControl11_CloseButtonClicked;
//Close the form when you received the notification
private void userControl11_CloseButtonClicked(object sender, EventArgs e)
{
this.Close();
}
To learn more about events, take a look at:
Handling and raising events
Standard .NET event pattern

Pass click event of child control to the parent control

I have a Windows form, having a pane, which contains another class, derived from Windows Forms. This is contained as a control within the pane. It contains two buttons within itself.
I'd like the events of the child control to be passed all the way to the parent window. For example, the child window in the pane has a Cancel button, which is supposed to close it. I'd like the parent control, i.e., the main window to close as well, but how can I intercept the button click event of the child control?
I can modify the child control, but only if there is no other way to achieve this in a proper way, I'd rather like to avoid it.
While you can interact with parent form directly from child like this.ParentForm.Close(), but it's better to raise some events by child control and subscribe for the events in parent form.
Raise event from Child:
public event EventHandler CloseButtonClicked;
protected virtual void OnCloseButtonClicked(EventArgs e)
{
CloseButtonClicked?.Invoke(this, e);
}
private void CloseButton_Click(object sender, EventArgs e)
{
OnCloseButtonClicked(e);
}
Note: To raise the XXXX event, that's enough to invoke the XXXX event delegate; the reason of creating the protected virtual OnXXXX is just to follow the pattern to let the derivers override the method and customize the behavior before/after raising the event.
Subscribe and use event in Parent:
//Subscribe for event using designer or in constructor or form load
this.userControl11.CloseButtonClicked += userControl11_CloseButtonClicked;
//Close the form when you received the notification
private void userControl11_CloseButtonClicked(object sender, EventArgs e)
{
this.Close();
}
To learn more about events, take a look at:
Handling and raising events
Standard .NET event pattern

How to check whether control is button or not?

How can I check that whether mouse pointer is pointing a button or some other control?
I want to perform a particular task when mouse hover/move a button.
I know I can set event on individual button. But isn't it possible to check the pointed/hover control is button?
The sender argument in an event method should have the information you need...
private void MyEventHandler(object sender, EventArgs args) {
if(sender is Button) {
//Do some stuff
}
}
I'm not sure if you mean: can I do this without event handlers for MouseHover in individual controls. If so, the answer is no.
But you can attach each contol's MouseHover event to just one event handler that could look like the one in Chris's answer. For convenience you could even do that programmatically by looping through the controls in the form's load event. (assuming this is winforms)

Windows Forms: detect the change of the focused control

I'm implementing copy-paste in a Windows Forms application.
I need to enable/disable the bar-buttons for this two operations when the user changes the focused element in the application.
I can find the current focused control using something like this: http://www.syncfusion.com/FAQ/windowsforms/faq_c41c.aspx#q1021q, but how can I detect that the focused control has changed?
In your form load event handler you could also loop through all of the controls contained in the form and for each focusable control add an event handler for the Enter event:
private void Form1_Load(object sender, EventArgs e)
{
foreach (Control control in Controls)
{
control.Enter += ControlReceivedFocus;
}
}
void ControlReceivedFocus(object sender, EventArgs e)
{
Debug.WriteLine(sender + " received focus.");
}
My proposal is to use Application.Idle event.
Write logic that enables/disables your buttons in Application.Idle event.
Subscribe to Application.Idle event on form shown event
Check button availability on button click (so you never pass accidental click under heavy load)
Do not forget to remove Idle handler on form disposing (or closing), because this is static event
Using this technique you will always have correct buttons state, and you not need to worry about subscribing to many controls events to detect focus change. This is also light-weight approach, because Idle event is raised only when application is not busy.
I think you should add an event handler to the control (or if you have many of the same type, subclass it, and override the appropriate OnChange handler). This way you won't have to 'find' the focused control (it will be given as the sender parameter), and the event will only arise when the change actually happened.
To detect the focus on a control you can create this event:
void MyGotFocus(object sender, EventArgs e)
{
if (sender is TextBox)
{
//TODO YOUR OPERATION
//FOR EXAMPLE
(sender as TextBox).SelectAll();
}
}
and the next step is to associate the control and event by code:
myText1.GotFocus += MyGotFocus;
myText2.GotFocus += MyGotFocus;

Raise LostFocus event on a control manually

I have a bunch of controls (textbox and combobox) on a form with toolstripcontainer and toolstripbuttons for save, cancel etc for edits. We are using .Net 3.5 SP1
There is bunch of logic written in control.lostfocus and control.leave events. These events are not being called when clicked on the toolstrip buttons. Is there a way to call these events manually when any of these buttons are pressed.
Thanks.
Kishore
[Edit]
This is how I solved the problem. Thanks Chris Marasti-Georg for the pointer. In the button click event I calling focus on the toolstrip instead of the button as the toolstripbutton does not have a focus event. We can access the toolstrip on which the button is placed using
((ToolStripButton)sender).Owner.Focus()
-Kishore
You could listen to the click events on the buttons, and in the handler call their focus method. That would (hopefully) cause the previously focused control to respond correctly. Add the following handler to each button's click event:
private void ButtonClick(object sender, EventArgs e) {
if(sender != null) {
sender.Focus();
}
}
You can extend those controls and then call the OnLostFocus and OnLeave protected methods of the base class...
I'd suggest moving the login to a method outside the event handler and calling that method...

Categories