Windows Forms: detect the change of the focused control - c#

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;

Related

Method for Focus Change

Is there a method which initiates on focus change and can be overridden?
My goal is for the program to fetch closest data automatically from database to input fields whenever user changes his focus/presses enter or tab when on corresponding field. I'm still looking for a way to do this when user selects an item by mouse.
I'm aware that this could be implemented on mouse click but I refuse to believe that there is not a general method for focus change.
What about something like this:
foreach(Control ctrl in this.Controls)
{
ctrl.Enter += new EventHandler(Focus_Changed); // Your method to fire
}
Iterate through all controls and add a enter-event. Bind this handler to your method.
Edit:
Just in case you are wondering why "Enter" and not "LostFocus" or something like that: From my knowledge not every control got focus-events. As I've seen so far "Enter" is presented for all. Maybe there are exceptions. Should be checked out...
You could use Control.Enter event and Control.Leave event for that purpose.
See on MSDN Control.Enter and
Control.Leave.
textBox1.Enter += textBox1_Enter;
textBox1.Leave += textBox1_Leave;
private void textBox1_Enter(object sender, System.EventArgs e)
{
// the control got focus
}
private void textBox1_Leave(object sender, System.EventArgs e)
{
// the control lost focus
}

How do I tell which control the mouse has been clicked over?

I have been looking around for a while for some code that tells what control the mouse has clicked. I have a Form with over 50 controls and I don't want to click each one to make a mouse clicked on. How would I do this?
You can use the Tag property of each control. So set it to something meaningful and on Click event do something like this:
(sender As Control).Tag
EDIT: Also you may do this:
foreach (Control item in this.Controls) //this IS YOUR CURRENT FORM
{
if ((sender as Control).Equals(item))
{
//Do what you want
}
}
Approach One: Individualized Handling
The mouse click event will actually be received by the control on which the mouse is clicked, so the only thing you need to do is handle the MouseClick event for that control. That makes sense if you want mouse clicks to do something different for each of your controls.
This is just the basic event-handling strategy that you should already be familiar with. The event handler method can be wired up either using the designer or manually via code, and looks like this:
private void myControl_MouseClick(object sender, MouseEventArgs e)
{
// do something when the myControl control is clicked
}
Approach Two: Consolidated Handling
If you want the same behavior on multiple controls, you would wire up a single event handler method to handle the MouseClick event for multiple controls. Then, from inside of the event handler method, you would use the sender parameter to identify the control that was clicked. For example, you could cast sender to a Control object and test the value of the Name property.
If you wanted all controls of a certain type to behave a certain way, and all controls of another type to behave a different way, you could have two event handler methods and wire the controls up accordingly by type.
The easiest way to do this is to wire up the event handler methods through code. The designer would work, but it would be overly tedious to use it for each of many controls. For example, in your form's constructor, you could loop over all of the controls and hook up your event handlers:
public MyForm()
{
this.InitializeComponent();
// Wire up your event handlers.
foreach (Control ctrl in this.Controls)
{
if (ctrl is Label)
{
// Wire all Label controls up to do one thing.
ctrl.MouseClick += new MouseEventHandler(LabelControls_MouseClick);
}
else if (ctrl is Button)
{
// Wire up all Button controls to do another thing.
ctrl.MouseClick += new MouseEventHandler(ButtonControls_MouseClick);
}
else
{
// And wire up the rest of the controls to do a third thing.
ctrl.MouseClick += new MouseEventHandler(OtherControls_MouseClick);
}
}
}
private void LabelControls_MouseClick(object sender, MouseEventArgs e)
{
// do something when a Label control is clicked
}
private void ButtonControls_MouseClick(object sender, MouseEventArgs e)
{
// do something when a Button control is clicked
}
private void OtherControls_MouseClick(object sender, MouseEventArgs e)
{
// do something when a control other than a Label or Button is clicked
}
Approach Three: Global Handling
If you've made all of these controls transparent (that is, transparent to mouse events, not visually transparent) so that mouse click events are handled at a higher level (i.e., by your form), you can use the Control.GetChildAtPoint method to determine the control that was clicked on. You just specify the coordinates of the location at which the mouse was clicked, and the method will return the child control (if any) that is located at that point.
private void myForm_MouseClick(object sender, MouseEventArgs e)
{
Control ctrl = Control.GetChildAtPoint(e.Location);
if (ctrl != null)
{
// do something with the clicked control
}
else
{
// if ctrl is null, then the parent form itself was clicked,
// rather than one of its child controls
}
}
I don't really recommend this approach, though, because it violates good object-oriented design. You have to write code to determine which control is which based on its unique properties, instead of just letting the runtime determine and handle that automatically.

Throwing events through objects

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.

Routing Key events to other control

Is there any standard way to route all Key events from the control A to other control B? I wish that the keyboard focus will still be on A however the event handler of A would trigger the all event handlers of B for the key events.
edit: Clarification: calling a specific event handler I wrote for B is not enough. I need to mimic the actual event. So for example I want that if a key is sent to a TextBox, it would be written to the TextBox. The solution given below does not do that (not to mention the fact that if new event handlers are added to B it completely fails).
I'm aware that WPF differentiates between logical focus and keyboard focus, but I need both focuses to remain on control A, but in a certain cases route its incoming event to other controls.
Couldn't you do something like this?
private void button1_Click(object sender, RoutedEventArgs e)
{
// Check if the event needs to be passed to button2's handler
if (conditionIsMet)
{
// Send the event to button2
button2.RaiseEvent(e);
}
else
{
// button1's "Click" code
}
}
private void button2_Click(object sender, RoutedEventArgs e)
{
// button2's "Click" code
}
Edit: Modified code to use the RaiseEvent() method to programmatically raise a specific event, rather than just calling the event handler for button2.

How do you determine when a button is clicked in the child on the parent - ASP.NET

In my child user control I have a gridview with an OnRowCommand eventhandler that is executed when Edit button is click. I want to set the visibility of an ASP.NET placeholder control in the parent to true when the Edit button is clicked in child control.
What would be the best way to accomplish this task?
Update:
After a little bit more research on the internets, I create a public event Eventhandler in my child control and rasied the event when the OnRowCommand event was fired. In my page_load event of my parent control, i mapped the child user control event to an private event in my parent control.
Child Control source code:
public event EventHandler MyEvent;
protected void MyGridView_OnRowCommand(object sender, GridViewCommandEventsArgs e)
{
if(MyEvent != null)
MyEvent(sender, e);
}
Parent Control source code:
protected void Page_Load(object sender, EventArgs e)
{
MyChildControl.MyEvent += new EventHandler(this.MyLocalEvent);
}
private void MyLocalEvent(object sender, EventArgs e)
{
MyPlaceHolder.Visible = true;
MyUpdatePanel.Update();
}
There are two methods in addition to bubbling the event worth considering:
a. Create a new event in your child user control. Listen to this event in the parent control. Fire this event in the child control.
b. Listen to the gridview event OnRowCommand in the parent control.
Approach a is superior because there is less of the abstraction leaking through. B is quick and dirty, but if this is a one-time-use user control, it will not have a negative impact.
Creating events is fairly easy, many programs include templates for events which mean they only thing you type is the name of the event (e.g. Resharper).
Off the top of my head I would either create a new event within the child user control that would fire off when OnRowCommand fires, or use OnBubbleEvent - I can't remember the exact name but it's something like that.

Categories