I created a user control that functions as a keyboard. I arranged the buttons in the control in the exact same manner as a keyboard, and set (ControlStyles.Selectable, false). This allows the focus to stay in a textbox that the user selected on the parent form. I also set the style of the user control to not be selectable. Everything works great when the user presses the buttons, but when the user control gets clicked, it steals the focus away from the textbox. Here is my code:
public partial class TouchKeyboard : UserControl
{
public TouchKeyboard()
{
InitializeComponent();
SetStyle(ControlStyles.Selectable, false);
}
private void TouchKeyboard_Load(object sender, EventArgs e)
{
foreach (var button in this.Controls.OfType<CustomControls.CustomButton>())
{
button.Click += new EventHandler(this.ButtonClick);
}
}
private void ButtonClick(object sender, EventArgs e)
{
var button = sender as CustomControls.CustomButton;
if (button.Name == "btnSpace")
{
SendKeys.Send(" ");
}
else
{
SendKeys.Send("{" + button.Text + "}");
}
}
}
Why would my user control steal focus when ControlStyles.Selectable is set to false?
After a few days of screwing with it, I finally figured it out. Since panels don't steal focus, I docked a panel in the User Control and placed my buttons inside it. That fixed the problem.
Related
I have Windows Form TestForm, and in my Form I have several labels that are only used to display some text.
I need to display a MessageBox.Show anytime the Form is clicked. So I have an event handler for the click, which looks like this:
private void TestForm_Click(object sender, EventArgs e)
{
MessageBox.Show("The form has been clicked");
}
Unfortunately, the click event doesn't fire when I click over a label in the Form. Is there a way to fix this, besides consuming the click event for the labels?
Thanks.
To use the same click event for all labels:
In the properties for each label, go to the Events (lightning bolt tab).
You will see (probably near the top) a label for Click, click the dropdown for this event, and you will be shown a list of handlers that you could use for that label.
Here's the Properties > Events > Click handler (bottom right):
Because all of your labels are of the same type, and produce the same EventArgs, you are able to use the same handler for all of them.
Then, when you are adding more Labels, just choose the event handler from the Click event dropdown:
Hope this helps!
To flesh out LarsTech's comment, I have used something like this in the past when I was having problems with labels overlapping each other and lack of true transparency in WinForms. What I did was make the labels invisible on the Form, then iterate through them in the Form's paint event, pull the information out of them and then use Graphics.DrawString to draw the text. That way you you will still be able see them in design mode.
This is a quick example of what I mean.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
foreach (var temp in this.Controls)
{
if (temp is Label) //Verify that control is a label
{
Label lbl =(Label)temp;
e.Graphics.DrawString(lbl.Text, lbl.Font, new SolidBrush(lbl.ForeColor), new Rectangle(lbl.Location, lbl.Size));
}
}
}
private void Form1_Click(object sender, EventArgs e)
{
MessageBox.Show("The Form has been clicked");
}
}
I noticed that by programmatically selecting a Tab in the Tab control selects a control contained in the tab page selected.Is it possible to change this behaviour. I have a control in a tabpage that I do not want to be selected when the its tab page is selected from a button click. I have a simple form with a tab control and two tab pages. When button1 is clicked the tab page 2 is selected but so is the datagridview contained in that tab page.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.GotFocus += DataGridView1_GotFocus;
}
private void DataGridView1_GotFocus(object sender, EventArgs e)
{
//this event is called from button1_click
}
private void button1_Click(object sender, EventArgs e)
{
tabControl1.SelectedTab = tabPage2;
}
}
By default when you select a tab (or even when you start a form) the control which is the first in your tab order is automatically focused. I am assuming this is what is happening here.
You can solve this by simply unfocusing the datagridView in question. There are multiple ways to do this. Firstly you can set focus to the control that you wish to be selected instead of the dataGridView. This can be done by:
myControl.Focus = True;
Or alternatively if you want non of the controls to be selected you can set the active control to Null:
ActiveControl = NULL;
Note: ActiveControl is a property which contains the current active control.
As to where this code should be placed. That is totally dependent upon you. You can do it as soon as you change the tab in the button click event. This is what I would prefer.
I am sure there are other kludges as well to acheive the same. Hope this helps.
Here is code to select tab
private void button1_Click(object sender, EventArgs e)
{
// we can select tab by tab name
tabControl1.SelectTab("tabPage2");
tabControl1.SelectedIndex = 1;
tabControl1.TabPages[0].Hide();
tabControl1.TabPages[1].Show();
}
In my program I have a user control that displays data on a window using a content presenter. I would like to simply set the cursor focus on a certain textBox in my window at startup.
Usually I would do this through the code-behind of the window, like this: textBox.Focus();
However, the textBox is defined in the user control, and doesn't seem to work the same way. So far I have tried the same method as above in the user control's code-behind.
Why doesn't this work? How do I set the focus if the textBox is defined in a user control?
What I have tried....:
User Control:
public UserControl()
{
InitializeComponent();
FocusManager.SetFocusedElement(this, textBox);
}
User Control:
public UserControl()
{
InitializeComponent();
textBox.Focusable = true;
Keyboard.Focus(textBox);
}
Give this a try: FocusManager.SetFocusedElement
FocusManager.SetFocusedElement(parentElement, textBox)
or from the msdn website:
textBox.Focusable = true;
Keyboard.Focus(textBox);
Note: You can't set focus in a constructor. If you are, UI Elements have not been created at that point. You should set focus during the Loaded event of your control.
A little bit late but what it really worked for my was
public UserControl()
{
InitializeComponent();
Dispatcher.BeginInvoke(new System.Action(() => { Keyboard.Focus(TextBox); }),
System.Windows.Threading.DispatcherPriority.Loaded);
}
You can try setting the focus in the Loaded or Initialized event of the User control. Eg:
private void MyWpfControl_Load(object sender, EventArgs e)
{
textBox.Focusable = true;
Keyboard.Focus(textBox);
}
Info: Loaded event or Initialized event
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)
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;
}
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");
}
}
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 textBoxs to it.
you can also do what windows is doing and use just one textbox like here:
if it's fits your needs
What about using this with the parameter forward = false?
Control.SelectNextControl Method
You'd probably call it on your "custom Number Keypad control".
I am using a windows form and within the form i have a user control with two labels, one that has a message ENTER AMOUNT and the other where I am putting the values typed by the user (like when you go to an ATM) it starts showing the number .. it works fine if i dont have any other controls on the user control.. but the moment i add a button it does not work, it wont start showing the numbers as I use my numeric key pad.. but if i remove whatever button i added it works again... Here is my user control code.
public partial class OperationAmount : UserControl
{
public OperationAmount()
{
InitializeComponent();
}
private int _inputNumber = 0;
private void OperationAmount_Load(object sender, EventArgs e)
{
}
private void Form_KeyAmountPressed(object sender, KeyPressEventArgs e)
{
if (!Char.IsNumber(e.KeyChar))
{
return;
}
else if (lblOperationAmount.Text.Length > 9)
{
return;
}
else
{
_inputNumber = 10 * _inputNumber + Int32.Parse(e.KeyChar.ToString());
ReformatOutput();
}
}
private void ReformatOutput()
{
lblOperationAmount.Text = String.Format("{0:0.00}", (double)_inputNumber / 100.0);
}
}
Probably the new control steals the keypresses from your Form_KeyAmountPressed method because now it has the focus and receive the event KeyPress.
A simple workaround would be to add the method Form_KeyAmountPressed also at the KeyPress event of the button. Try also to set the TabStop property of the button to false. (not sure if this has any effect when the button is the only control that can get focus on your user control).