Reputation: 1716
I have made a custom Number Keypad control that I want to place in my winform application. All of the buttons have an OnClick
event to send a value to the focused textbox in my form where I have placed my custom control. Like this:
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null && focusedCtrl is TextBox)
{
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
focusedCtrl
is supposed to be set on the MouseDown
event of the button like this:
private void btnNum1_MouseDown(object sender, EventArgs e)
{
focusedCtrl = this.ActiveControl;
}
where this.ActiveControl
represents the active control on the form.
My problem is that the button always receives the focus before the event detects what the focused control was previously. How can I detect which control had the focus before the button got the focus? Is there another event I should be using? Thanks in advance!
EDIT: Also, I would rather not use the GotFocus
event on each textbox in the form to set focusedCtrl
since that can be tedious and because I would like to have all the coding of my custom control be in the control itself and not on the form where it is placed. (I will do this, though, if there is no other practical way to do what I am asking)
Upvotes: 4
Views: 7051
Reputation: 942338
Your requirement is fairly unwise, you'll want some kind of guarantee that your button isn't going to poke text into inappropriate places. You really do need to have the form co-operate, only it knows what places are appropriate.
But it is not impossible, you can sniff at input events before they are dispatched to the control with the focus. In other words, record which control has the focus before the focusing event is fired. That's possible in Winforms with the IMessageFilter interface.
Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing your existing buttons.
using System;
using System.Windows.Forms;
class CalculatorButton : Button, IMessageFilter {
public string Digit { get; set; }
protected override void OnClick(EventArgs e) {
var box = lastFocused as TextBoxBase;
if (box != null) {
box.AppendText(this.Digit);
box.SelectionStart = box.Text.Length;
box.Focus();
}
base.OnClick(e);
}
protected override void OnHandleCreated(EventArgs e) {
if (!this.DesignMode) Application.AddMessageFilter(this);
base.OnHandleCreated(e);
}
protected override void OnHandleDestroyed(EventArgs e) {
Application.RemoveMessageFilter(this);
base.OnHandleDestroyed(e);
}
bool IMessageFilter.PreFilterMessage(ref Message m) {
var focused = this.FindForm().ActiveControl;
if (focused != null && focused.GetType() != this.GetType()) lastFocused = focused;
return false;
}
private Control lastFocused;
}
Upvotes: 3
Reputation: 8793
What about using this with the parameter forward = false?
Control.SelectNextControl Method
You'd probably call it on your "custom Number Keypad control".
Upvotes: 0
Reputation: 11597
you have an event called lostFocus you can use
button1.LostFocus +=new EventHandler(dataGridView1_LostFocus);
and in the event:
Control lastFocused;
void dataGridView1_LostFocus(object sender, EventArgs e)
{
lastFocused = sender as Control;
}
in that way you can always know what is the Control that was focused previously
now, correct me if i'm wrong, but you do it for the SendKeys.Send("1");
to know which textBox
need to receive the number. for that you can use GotFocus
event and register only the textBox
s to it.
you can also do what windows is doing and use just one textbox like here:
if it's fits your needs
Upvotes: 2
Reputation: 63377
Control focusedCtrl;
//Enter event handler for all your TextBoxes
private void TextBoxesEnter(object sender, EventArgs e){
focusedCtrl = sender as TextBox;
}
//Click event handler for your btnNum1
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null){
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
Upvotes: 2