I am creating a entry page for kiosk device using WPF. There a 3 text boxes in the page and keyboard(created using buttons). To perform the action when we press the key board button in want to display the text in the corresponding text box.
Need: How to find the currently focused text box.
code using:
void buttonElement_Click(object sender, RoutedEventArgs e)
{
// create variable for holding string
String sendString = "";
try
{
// stop all event handling
e.Handled = true;
Button btn = ((Button)sender);
// set sendstring to key
if (btn.Content.ToString().Length == 1 && btn.CommandParameter.ToString() != btn.Content.ToString())
{
sendString = btn.Content.ToString();
}
else
{
sendString = btn.CommandParameter.ToString();
}
// sendString = ((Button)sender).CommandParameter.ToString();
int position = txtAuto.SelectionStart;
// if something to send
if (!String.IsNullOrEmpty(sendString))
{
// if sending a string
if (sendString.Length > 1)
{
switch (sendString)
{
case "Del":
if (position != txtAuto.Text.Length)
{
txtAuto.Text = txtAuto.Text.Remove(position, 1);
txtAuto.SelectionStart = position;
}
break;
case "BACKSPACE":
if (position != 0)
{
txtAuto.Text = txtAuto.Text.Remove(position - 1, 1);
txtAuto.SelectionStart = position;
}
break;
case "Clear":
txtAuto.Text = string.Empty;
break;
case "ENTER":
popup.IsOpen = false;
// lbSuggestion.ItemsSource = null;
this.FetchSearchResult(txtAuto.Text.Trim());
if (lbResult.Items.Count != 0)
{
lbResult.ScrollIntoView(lbResult.Items[0]);
}
break;
}
}
else
{
txtAuto.Text = txtAuto.Text.Insert(txtAuto.SelectionStart, sendString);
txtAuto.SelectionStart = position + 1;
}
// set keyboard focus
System.Windows.Input.Keyboard.Focus(this.txtAuto);
// set normal focus
this.txtAuto.Focus();
}
}
catch (Exception)
{
// do nothing - not important for now
Console.WriteLine("Could not send key press: {0}", sendString);
}
}
This code is working fine for single textbox how to make it work for other textboxes.
Normaly the focus got lost if you click a button. So you can "save" the last focused text box in a class variable if a textbox is loosing the focus.
private TextBox _currentTextbox;
private void TextBoxLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_currentTextbox = e.Source as TextBox;
}
attach this handler to all Text boxes and use _currentTextbox in your function.
See more at http://msdn.microsoft.com/en-us/library/aa969768.aspx
Need: How to find the currently focused text box.
You can use the FocusManager.GetFocusedElement method.
When you click the button, the button receives the focus and the textbox loses it. So, one approach would be to subscribe to the LostFocus events of all textboxes and remember which one lost the focus. The one that lost the focus last is the one that lost the focus because of the button click and hence was the one that had the focus before the click.
Related
I'm creating Windows Forms Application that creates mathematical tasks for children. I have dynamically created a list of 10 tasks represented by labels, and beside every label there is a Text Box, also dynamically created. I have one button "Confirm", for users to confirm all the answers once, but now I want to check if any of Text Box is empty, and if is I want to generate label to say "Must not be empty", keep the button "Confirm", and when user start typing that Text Box I want label to be lost, because it is no longer empty. After user populate all Text Boxes, by clicking the "Confirm" button, app continue with logic based on all inputs.
Here is the code where I check is there a empty Text Box in my User Control called UCFirstLevelAddition:
public void submitBtn_Click(object sender, EventArgs e)
{
bool thereAreEmptyContainers = logic.EmptyContainerCheck(this);
if (thereAreEmptyContainers)
{
logic.CreateEmptyContainerLabels(this);
}
else if (!thereAreEmptyContainers)
{
userAnswerList = logic.CreateUserAnswersList(this);
userAnswerListInt = logic.ConvertUserAnswerListToInt(userAnswerList);
al1AreYouShurePanel.Visible = true;
}
}
My EmptyContainerCheck() method is in another Class and looks like:
public bool EmptyContainerCheck(UCFirstLevelAddition userControl)
{
bool output=false;
foreach (Control c in userControl.Controls)
{
if (c is TextBox)
{
TextBox container = c as TextBox;
if (container.Text.Length == 0)
{
output = true;
}
}
}
return output;
}
So, when this method return true, I am doing CreateEmptyContainerLables() that looks like:
public void CreateEmptyContainerLabels(UCFirstLevelAddition userControl)
{
int x = 550, y = 180;
Label message = new Label();
foreach (Control c in userControl.Controls)
{
if (c is TextBox)
{
TextBox container = c as TextBox;
if (container.Text.Length == 0)
{
message.Text = string.Format("Ne sme biti prazno!");
message.Width = 400;
message.ForeColor = Color.Red;
message.Location = new Point(x, y + 40);
}
else { userControl.Controls.Remove(message); }
userControl.Controls.Add(message);
y = y + 60;
}
}
}
But this does not work as it should be. Can anyone give me a tip?
Thank you in advance!
We have a DataGridView with data in a form. To enable quick search, we added TextBox to DataGridView.Controls and highlight cells which contain text from TextBox.
However, there is an issue. DataGridView consumes the Left arrow ←, Right arrow →, Home and End (with or without Shift) keys even if the cursor is in TextBox, and the user cannot change the caret position or select text from the keyboard.
TextBox generates a PreviewKeyDown event and nothing more happens.
Simplified code:
public partial class TestForm : Form
{
public TestForm()
{
InitializeComponent();
Width = 400;
Height = 400;
var txt = new TextBox { Dock = DockStyle.Bottom, BackColor = Color.Khaki };
var dgv = new DataGridView
{
Dock = DockStyle.Fill,
ColumnCount = 3,
RowCount = 5
};
dgv.Controls.Add(txt);
Controls.Add(dgv);
dgv.PreviewKeyDown += DgvOnPreviewKeyDown;
dgv.KeyDown += DgvOnKeyDown;
txt.PreviewKeyDown += TxtOnPreviewKeyDown;
txt.KeyDown += TxtOnKeyDown;
}
private void DgvOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
Debug.WriteLine(String.Format("Dgv Key Preview {0}", e.KeyCode));
e.IsInputKey = true;
}
private void DgvOnKeyDown(object sender, KeyEventArgs e)
{
Debug.WriteLine(String.Format("Dgv Key {0}", e.KeyCode));
}
private void TxtOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
Debug.WriteLine(String.Format("Txt Key Preview {0}", e.KeyCode));
}
private void TxtOnKeyDown(object sender, KeyEventArgs e)
{
Debug.WriteLine(String.Format("Txt Key {0}", e.KeyCode));
}
}
Type 123 in TextBox and then try the Right arrow, Left arrow, End, or Home. DataGridView change the selected cell, but the TextBox caret doesn't move.
TextBox works just fine if not inside a DataGridView (no problem at all when using the same method adding it into TreeView for example). TextBox acts similar to the Quick search Panel in the browser and has to be on top of the DataGridView. Adding a TextBox to a Form (or to be more specific, to a DataGridView parent) creates its own set of issues (tracking Location, Size, Visibility, ...) and is not acceptable.
What can be done to make sure that TextBox receive those keys and change the caret position or select text?
TextBox works just fine if not inside DataGridView (no problem at all when using the same method adding it into TreeView for example)
Apparently the problem is in DataGridView. It's because DataGridView overrides the Control.ProcessKeyPreview method:
This method is called by a child control when the child control receives a keyboard message. The child control calls this method before generating any keyboard events for the message. If this method returns true, the child control considers the message processed and does not generate any keyboard events.
The DataGridView implementation does just that - it maintains zero or one child controls internally (EditingControl), and when there is no such control active, it handles many keys (navigation, tab, enter, escape, etc.) by returning true, thus preventing the child TextBox keyboard events generation. The return value is controlled by the ProcessDataGridViewKey method.
Since the method is virtual, you can replace the DataGridView with a custom derived class which overrides the aforementioned method and prevents the undesired behavior when neither the view nor the view active editor (if any) has the keyboard focus.
Something like this:
public class CustomDataGridView : DataGridView
{
bool SuppressDataGridViewKeyProcessing => ContainsFocus && !Focused &&
(EditingControl == null || !EditingControl.ContainsFocus);
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (SuppressDataGridViewKeyProcessing) return false;
return base.ProcessDataGridViewKey(e);
}
}
The above is just the half of the story and solves the cursor navigation and selection keys issue. However DataGridView intercepts another key message preprocessing infrastructure method - Control.ProcessDialogKey and handles Tab, Esc, Return, etc. keys there. So in order to prevent that, the method has to be overridden as well and redirected to the parent of the data grid view. The later needs a little reflection trickery to call a protected method, but using one time compiled delegate at least avoids the performance hit.
With that addition, the final custom class would be like this:
public class CustomDataGridView : DataGridView
{
bool SuppressDataGridViewKeyProcessing => ContainsFocus && !Focused &&
(EditingControl == null || !EditingControl.ContainsFocus);
protected override bool ProcessDataGridViewKey(KeyEventArgs e)
{
if (SuppressDataGridViewKeyProcessing) return false;
return base.ProcessDataGridViewKey(e);
}
protected override bool ProcessDialogKey(Keys keyData)
{
if (SuppressDataGridViewKeyProcessing)
{
if (Parent != null) return DefaultProcessDialogKey(Parent, keyData);
return false;
}
return base.ProcessDialogKey(keyData);
}
static readonly Func<Control, Keys, bool> DefaultProcessDialogKey =
(Func<Control, Keys, bool>)Delegate.CreateDelegate(typeof(Func<Control, Keys, bool>),
typeof(Control).GetMethod(nameof(ProcessDialogKey), BindingFlags.NonPublic | BindingFlags.Instance));
}
You can try this.
I created my own textbox and overrode method ProcessKeyMessage.
public class MyTextBox : TextBox
{
private const int WM_KEYDOWN = 0x0100;
private const int WM_SYSKEYDOWN = 0x0104;
protected override bool ProcessKeyMessage(ref Message m)
{
if (m.Msg != WM_SYSKEYDOWN && m.Msg != WM_KEYDOWN)
{
return base.ProcessKeyMessage(ref m);
}
Keys keyData = (Keys)((int)m.WParam);
switch (keyData)
{
case Keys.Left:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.ShiftKey:
return base.ProcessKeyEventArgs(ref m);
default:
return base.ProcessKeyMessage(ref m);
}
}
}
And then you can call:
var txt = new MyTextBox { Dock = DockStyle.Bottom, BackColor = Color.Khaki };
Try to just add the TextBox to the main form instead of the DataGridView:
Controls.Add(txt);
Controls.Add(dgv);
txt.PreviewKeyDown += DgvOnPreviewKeyDown;
txt.KeyDown += DgvOnKeyDown;
txt.PreviewKeyDown += TxtOnPreviewKeyDown;
txt.KeyDown += TxtOnKeyDown;
It sounds a bit like an exercise in futility.
It may be easier to encapsulate the behavior of both the TextBox and DataGridView controls by placing them into a UserControl together with a little code to handle events.
Here is a partial solution to the issue. TextBox still doesn't receive navigation keys input natively, but I reproduced a normal caret and selection behavior.
PreviewKeyDownEventArgs contains information about the pressed key and modifiers (Shift). For each key combination I set a new SelectionStart and SelectionLength for the TextBox.
private void TxtOnPreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
TextBox txt = (TextBox)sender;
if (e.KeyCode == Keys.Home)
{
int idx = txt.SelectionStart;
txt.SelectionStart = 0;
txt.SelectionLength = e.Shift ? idx : 0;
}
else if (e.KeyCode == Keys.End)
{
int idx = txt.SelectionStart;
if (e.Shift)
txt.SelectionLength = txt.TextLength - idx;
else
{
txt.SelectionStart = txt.TextLength;
txt.SelectionLength = 0;
}
}
else if (e.KeyCode == Keys.Left)
{
if (e.Shift)
{
if (txt.SelectionStart > 0)
{
txt.SelectionStart--;
txt.SelectionLength++;
}
}
else
{
txt.SelectionStart = Math.Max(0, txt.SelectionStart - 1);
txt.SelectionLength = 0;
}
}
else if (e.KeyCode == Keys.Right)
{
if (e.Shift)
txt.SelectionLength++;
else
{
txt.SelectionStart = Math.Min(txt.TextLength, txt.SelectionStart + 1);
txt.SelectionLength = 0;
}
}
}
I am trying to notify the user when some Keys are pressed. If Caps, Num, Scroll and Insert are pressed, the relative BarStaticItem (the application uses some devexpress controls) changes color to White.
void DxMainWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.CapsLock)
{
if (e.KeyboardDevice.IsKeyToggled(Key.CapsLock))
{
bCaps.Tag = new SolidColorBrush(Colors.White);
}
else
{
bCaps.Tag = new SolidColorBrush(Colors.DarkGray);
}
}
if (e.Key == Key.NumLock)
{
if (e.KeyboardDevice.IsKeyToggled(Key.NumLock))
{
bNum.Tag = new SolidColorBrush(Colors.White);
}
else
{
bNum.Tag = new SolidColorBrush(Colors.DarkGray);
}
}
if (e.Key == Key.Scroll)
{
if (e.KeyboardDevice.IsKeyToggled(Key.Scroll))
{
bScrl.Tag = new SolidColorBrush(Colors.White);
}
else
{
bScrl.Tag = new SolidColorBrush(Colors.DarkGray);
}
}
if (e.Key == Key.Insert)
{
if (e.KeyboardDevice.IsKeyToggled(Key.Insert))
{
bIns.Tag = new SolidColorBrush(Colors.White);
}
else
{
bIns.Tag = new SolidColorBrush(Colors.DarkGray);
}
}
}
Everything works fine but when i press Insert inside a TextBox it does not work. The weird thing is that in dispute of the other KeyEvents the event for Insert is like never happening (breakpoint does not break), even if the functionality works fine (overwrite text when pressed etc).
Can someone explain me why?
Thanks.
The Insert key is handled by the TextBox control, so that the event is not routed up the UI element tree.
You may however attach a handler for the PreviewKeyDown event instead of KeyDown:
<Window ... PreviewKeyDown="DxMainWindow_KeyDown">
Please refer to the Routed Events Overview article on MSDN for more details.
Quit Button Click Event.
`void buttn2_Click(object sender, EventArgs e) //QUIT BUTTON CLICK EVENT.
{
if (MessageBox.Show("LEAVE CURRENT GAME?", "QUIT CONFIRMATION", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
this.Controls.Remove(buttn); .. PLAY AGAIN BUTTON.
this.Controls.Remove(buttn2);
for (int i = 0; i <= gencount; i++)
{
this.Controls.Remove(panel[i]);
this.Controls.Remove(label200[i]);
this.Controls.Remove(label100[i]);
this.Controls.Remove(Tbox[i]);
}
this.Controls.Remove(AttemptsRem);
this.Controls.Remove(AttemptNum);
this.Controls.Remove(TimeRem);
this.Controls.Remove(Min);
this.Controls.Remove(Sec);
this.Controls.Remove(misc);
this.ReftoForm2.Show(); To go back to the starting form
}
else
buttn.Focus();
}
Form1 activate Event.
private void Form1_Activated(object sender, EventArgs e)
{
if (ui_formCowsAndBulls.rdbSinglePlayer.Checked == true)//Static variable
{
//GetAllTheWords(); .. Am still working on getting a the 4 letter words
//GetDistinctElements(); .. randomly out of a list.
textBox1.PasswordChar = '*';
textBox1.Focus();
foreach (string val in distinctWords)
{
if (val == "ABLE") .. For single player,the guess word is ABLE.
textBox1.Text = val;
}
}
else
{
textBox1.Text = string.Empty;
textBox1.Enabled = true;
textBox1.Focus();
}
//textBox1.Focus();
}
PLAY AGAIN CLICK EVENT
private void buttn_Click(object sender, EventArgs e) //PLAY AGAIN CLICK EVENT.
{
for (int i = 0; i <= gencount; i++)
{
this.Controls.Remove(panel[i]);
this.Controls.Remove(label200[i]);
this.Controls.Remove(label100[i]);
this.Controls.Remove(Tbox[i]);
}
this.Controls.Remove(AttemptsRem);
this.Controls.Remove(AttemptNum);
textBox1.Text = string.Empty;
textBox1.Enabled = true;
textBox1.Focus();
incrpanel = 0; gencount = 0; count = 10;
this.Controls.Remove(TimeRem);
this.Controls.Remove(Min);
this.Controls.Remove(Sec);
this.Controls.Remove(misc);
this.textBox1.PasswordChar = '*';
this.Controls.Remove(buttn);
this.Controls.Remove(buttn2);
}
My question is I dont come out of the message boxes when I click message box button NO.I come out of the message box the first time I play the game,But If i play the game a second time,it takes me two clicks to come out of the Message box.If I play the game a third time,it takes me 3 clicks on either the Yes or NO button to come out of the Message Box.I hope you folks can help me.I had posted the same question before but without the code.Hope the code helps.
I think you may be subscribing to the Click-event:
button1.Click += new EventHandler(buttn2_Click);
in a place in the code where it's called more than once, so when the button is clicked the MessageBox will be shown, and when the buttn2_Click event handler (-your code that you posted) is finished - it will run again, showing another MessageBox, for as many times as the subscription (the "...+=..." above) was done.
I can't seem to prevent my form from checking one of the Radio Buttons in my Group Box:
As shown in the designer, no Radio Buttons are checked there.
Below is just about all of the code for this simple form. Nothing calls for a Radio Buttons to be checked here or in the form's designer.
Q: Is there a way to prevent any Radio Button from being checked when the form loads?
public ValueTypeSelector() {
InitializeComponent();
radioButton1.Checked = false;
radioButton2.Checked = false;
radioButton3.Checked = false;
radioButton4.Checked = false;
radioButton5.Checked = false;
radioButton6.Checked = false;
button1.Enabled = false;
button1.Click += clickEvent;
button2.Click += clickEvent;
radioButton1.Click += clickEvent;
radioButton2.Click += clickEvent;
radioButton3.Click += clickEvent;
radioButton4.Click += clickEvent;
radioButton5.Click += clickEvent;
radioButton6.Click += clickEvent;
}
void OnShow(object sender, EventArgs e) {
foreach (RadioButton rad in Controls) {
if (rad.Checked) {
Console.WriteLine("WTF?");
}
}
}
void clickEvent(object sender, EventArgs e) {
RadioButton rad = sender as RadioButton;
if (rad != null) {
if (rad.Checked) {
if (rad == radioButton1) {
DataType = TableDataType.Boolean; // <= HERE IS THE PROBLEM! FIRES ON FORM LOAD
} else if (rad == radioButton2) {
DataType = TableDataType.Character;
} else if (rad == radioButton3) {
DataType = TableDataType.DateTime;
} else if (rad == radioButton4) {
DataType = TableDataType.Decimal;
} else if (rad == radioButton5) {
DataType = TableDataType.Integer;
} else if (rad == radioButton6) {
DataType = TableDataType.String;
} else {
return;
}
button1.Enabled = true;
}
} else if (sender == button1) {
DialogResult = DialogResult.OK;
Close();
} else if (sender == button2) {
DialogResult = DialogResult.Cancel;
Close();
}
}
UPDATE: The problem is that radioButton1 gets checked when the form is shown:
if (rad == radioButton1) {
DataType = TableDataType.Boolean; // <= HERE IS THE PROBLEM! FIRES ON FORM LOAD
} else if (rad == radioButton2) {
Make sure your radiobuttons are NOT the first tabindex = 0 controls. Make the OK button tabindex=0, followed by the radiobuttons.
In the design mode, you'll find the AutoCheck property set to true. Just turn it to false. It won't be checked untill you select it manually during the runtime.
Set TabStop=False in properties.
Set the checked state to false after form load. Put this in Shown event and see if it working.
I think this might actually be a bug in VS. I'm using 2010 SP1 but OP doesn't mention which version they're using.
Had the same phantomness happening in one of my apps.
Changed Autochecked for the two radio buttons to False, built the app. The affected buttons were now not selected, but other ones previously unaffected were now selected.
Went back into code and turned autocheck to true on the original buttons, and then toggled from true to false and back again on the newly affected buttons. Re ran and the app was fine; no buttons selected.
When I first checked the tabIndexes for the original radio buttons they were set to tabIndex 0; which I changed, so that could also be part of the mix.