I have previously asked a question on how to Selecting dynamically created Listboxs items in C# which was answered. The problem now is that when the listbox gets the focus when popped up! I can't continue typing unless I either select an item or press Esc, which I have explicitly defined to set focus back to my TextBox.
The irony is that I have a condition in my KeyDown event which says if the UP or Down arrow keys are pressed, set the focus on ListBox so that user can choose an item, but don't transfer the focus so that user can continue typing freely.
Just like what we have on Visual Studio, when a user presses a dot, he is not blocked and forced to choose an item form the Intellisense list, but he can continue typing and or at any time use arrow keys UP or Down to select the proper item.
I can't achieve the same functionality using the code below. How can I get this to work as mentioned?
I need to say that using ActiveControl, and transferFocus, using this.Focus() prior to lst.Focus(), disabling and enabling textbox they all didn't work!
private void txtResults_KeyDown(object sender, KeyEventArgs e)
{
string[] words= ((TextBox)sender).Text.Split(' ');
string s = sampleWord.Text = words[words.Length - 1];
if (e.KeyCode == Keys.OemPeriod)
{
ShowPopUpList(s);
lst.Focus(); //This transfers the focus to listbox but then prevents user
//from being able to type anymore unless he/she chooses an item!
}
else if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
{
lst.Focus();//doesnt work :-/
}
else
{
lst.Hide();
txtResults.Focus();
}
}
This behavior is happening because you are shifting focus to the listbox. Try thinking about it differently and instead of giving focus to the listbox, select the next/previous item in the list when the up or down arrows are pressed.
change your "else if" to the following:
else if (e.KeyCode == Keys.Down)
{
if (lst.SelectedIndex + 1 < lst.Items.Count)
{
lst.SelectedIndex += 1;
}
e.Handled = true;
}
else if (e.KeyCode == Keys.Up)
{
if (lst.SelectedIndex - 1 >= 0)
{
lst.SelectedIndex -= 1;
}
e.Handled = true;
}
If you want the user to be able to continue typing in the textbox while still manipulating the selection of the listbox, then you will have to fake it: don't actually set focus to the listbox when you show it. Instead, change the selection of the listbox manually in the KeyDown event for the textbox. Something like this:
private void txtResults_KeyDown(object sender, KeyEventArgs e)
{
string[] words = ((TextBox)sender).Text.Split(' ');
string s = sampleWord.Text = words[words.Length - 1];
if (e.KeyCode == Keys.OemPeriod)
{
ShowPopUpList(s);
lst.SelectedIndex = 0;
}
else if (lst.Visible && e.KeyCode == Keys.Up)
{
// manipulate the selection on the listbox (move up)
if (lst.SelectedIndex > 0)
lst.SelectedIndex -= 1;
// eat the keypress so it textbox doesn't get it and move the cursor
e.Handled = true;
}
else if (lst.Visible && e.KeyCode == Keys.Down)
{
// manipulate the selection on the listbox (move down)
if (lst.SelectedIndex < lst.Items.Count - 1)
lst.SelectedIndex += 1;
// eat the keypress so it textbox doesn't get it and move the cursor
e.Handled = true;
}
else if (lst.Visible && e.KeyCode == Keys.Enter)
{
// insert current list box selection into text box and hide the list
txtResults.Text += lst.SelectedItem;
txtResults.SelectionStart = txtResults.Text.Length;
lst.Hide();
// eat the keypress to prevent the textbox (and the form) from acting on it
e.SuppressKeyPress = true;
e.Handled = true;
}
else
{
lst.Hide();
}
}
You don't need to focus your ListBox to allow your user to select its item using Arrow keys, your TextBox should always be focused, You have to process the Enter right in the KeyDown event handler of your TextBox, add the selected item there not in the KeyDown event handler of your ListBox, something like this:
private void txtResults_KeyDown(object sender, KeyEventArgs e)
{
string[] words= ((TextBox)sender).Text.Split(' ');
string s = sampleWord.Text = words[words.Length - 1];
if (e.KeyCode == Keys.OemPeriod)
{
ShowPopUpList(s);//Show your ListBox without needing to focus it.
}
if(lst.Visible){
if(e.KeyCode == Keys.Down){
lst.SelectedIndex = (lst.SelectedIndex + 1) % lst.Items.Count;
}
else if (e.KeyCode == Keys.Up){
lst.SelectedIndex = lst.SelectedIndex == 0 ? lst.Items.Count - 1 : lst.SelectedIndex - 1
}
else if (e.KeyCode == Keys.Enter){//Add the selected Item
//Add the selected Item here not in the KeyDown event handler of your ListBox
//.........
//.........
//Your TextBox may not need to handle the Enter, so just suppress it after adding the selected item
e.Handled = true;
}
else
{
lst.Hide();
}
}
}
Related
I have a textbox in my form that I am using as a search bar for my listbox. Currently I have the textbox set up to actively select an item in the listbox while you type with the following code:
private void TextBox1_TextChanged(object sender, EventArgs e)
{
var textBox = (TextBox)sender;
listBox1.SelectedIndex = textBox.TextLength == 0 ?
-1 : listBox1.FindString(textBox.Text);
}
What I would like to accomplish is to be able to also use the up & down arrow keys to adjust what is selected. For example if the listbox contains two items: Test1 & Test2 when you begin typing "t" test1 will be selected. Opposed to having to finish typing "test2" to change what is selected I would like to be able to type "t" then press the down arrow key to select test2 however keep the focus in the textbox.
I have tried using the following, however when pressing the up or down arrow key the cursor in the textbox adjusts instead of the selectedIndex
private void TextBox1_KeyUp(object sender, KeyEventArgs e)
{
int index = listBox1.SelectedIndex;
index = index--;
listBox1.SelectedIndex = index;
}
private void TextBox1_KeyDown(object sender, KeyEventArgs e)
{
int index = listBox1.SelectedIndex;
index = index++;
listBox1.SelectedIndex = index;
}
You got confused by the event name.
KeyUp and KeyDown refers to pushing a keyboard button up and down, not pressing up and down arrows. To do what you are looking for, you would need either one of them, e.g: KeyUp like follows:
private void TextBox1_KeyUp(object sender, KeyEventArgs e)
{
int index = listBox1.SelectedIndex;
if(e.KeyCode == Keys.Up)
{
index--;
}
else if(e.KeyCode == Keys.Down)
{
index++;
}
listBox1.SelectedIndex = index;
}
#Sohaib Jundi THANK YOU!!! This cleared things up beyond belief! I ended up adjusting the code slightly to fix an error that was occurring, as well as a little bug the cursor was having in case anyone else runs into anything similar to this.
private void TextBox1_KeyUp(object sender, KeyEventArgs e)
{
int index = listBox1.SelectedIndex;
int indexErrorFix = listBox1.Items.Count;
if (e.KeyCode == Keys.Up)
{
index--;
}
else if (e.KeyCode == Keys.Down)
{
index++;
}
if (index < indexErrorFix && index >= 0)
{
listBox1.SelectedIndex = index;
}
else { }
textBox1.SelectionStart = textBox1.Text.Length;
}
I'm currently trying to increase the index of the cursor by 1. For example, if my blinking cursor was between 2 and 1 in 210, it would increase the value to 220.
This is part of the code I'm using right now. I'm trying to get the cursor to stay in its place after pressing down, and its moving to the right. I tried to set the SelectionStart back to 0 but the box increases it by 1 by default (my textbox's first caret index starts on the very left).
TextBox textBox = (TextBox)sender;
int box_int = 0;
Int32.TryParse(textBox.Text, out box_int);
if (e.KeyCode == Keys.Down)
{
if(textBox.SelectionStart == 0)
{
box_int -= 10000;
textBox.Text = box_int.ToString();
textBox.SelectionStart= 0;
return;
}
}
In order to prevent the caret (not the cursor) from moving, you should set e.Handled = true; in your event handler. This code changes the digit to the right of the caret when the up or down arrow is pressed. If the up or down arrow is pressed, the e.Handled is set to true to prevent the movement of the caret. This code is not fully tested, but seems to work. I also set the textbox ReadOnly property to true and preset the value to "0".
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = (TextBox)sender;
//Only change the digit if there is no selection
if (textBox.SelectionLength == 0)
{
//Save the current caret position to restore it later
int selStart = textBox.SelectionStart;
//These next few lines determines how much to add or subtract
//from the value based on the caret position in the number.
int box_int = 0;
Int32.TryParse(textBox.Text, out box_int);
int powerOf10 = textBox.Text.Length - textBox.SelectionStart - 1;
//If the number is negative, the SelectionStart will be off by one
if (box_int < 0)
{
powerOf10++;
}
//Calculate the amount to change the textbox value by.
int valueChange = (int)Math.Pow(10.0, (double)powerOf10);
if (e.KeyCode == Keys.Down)
{
box_int -= valueChange;
e.Handled = true;
}
if (e.KeyCode == Keys.Up)
{
box_int += valueChange;
e.Handled = true;
}
textBox.Text = box_int.ToString();
textBox.SelectionStart = selStart;
}
}
I dynamically created a Listbox and filled it with some items, Upon typing a dot in a Textbox i want to show the Listbox so that the user can select any item by using arrow keys .
I did everything up to this point. When the user types a dot in the Textbox, The Listbox gets shown, But the arrow keys wont select any items!
private void txtResults_KeyDown(object sender, KeyEventArgs e)
{
string[] words= ((TextBox)sender).Text.Split(' ');
string s = sampleWord.Text = words[words.Length - 1];
if (e.KeyCode == Keys.OemPeriod)
{
ShowPopUpList(s);
}
else if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
{
lst.Focus();//doesnt work :-/
}
else
{
lst.Hide();
txtResults.Focus();
}
}
This is the code for creating the listbox on FormLoad()
private void CreateListBox()
{
lst = new ListBox();
lst.Size = new Size(70, 130);
lst.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
lst.KeyDown += lst_KeyDown;
lst.DoubleClick += lst_DoubleClick;
//adding some test input
lst.Items.Add("بسم");
lst.Items.Add("الله ");
lst.Items.Add("الرحمن ");
lst.Items.Add("الرحیم ");
lst.Items.Add("بنام ");
lst.Items.Add("خداوند ");
lst.Items.Add("بخشنده ");
lst.Items.Add("مهربان ");
lst.Items.Add("الهی شکرت ");
}
private void ShowListbox()
{
txtResults.SelectionStart = txtResults.Text.Length;
txtResults.SelectionLength = 0;
Point index = txtResults.GetPositionFromCharIndex(txtResults.SelectionStart-1);
lst.Location = new Point (index.X-50, index.Y+70);
this.Controls.Add(lst);
lst.BringToFront();
lst.Show();
}
In ShowPopUpList(s) the ShowListbox() method is called. nothing fancy about it!
Note:
I only need the list box to get focus when i use UP or DOWN arrow keys to explicitly select an item. unless then i need to be able to freely continue typing and dont lose focus to listbox.
Whats the way around doing it ?
Remove focus from the textbox keydown handler and place it here:
private void ShowPopUpList(string s)
{
//your initialization of the
//listbox here and after..
listBox1.Focus();
}
Another way:
if (e.KeyCode == Keys.OemPeriod)
{
ShowPopUpList(s);
listBox1.Focus();
}
The real big difference is it gets focus rightaway.with your old code would first check the keydown and on the second hit it would already contain the focus.
Final Edit:
If Listbox needs to get the focus on up/down arrow keys(and only with those keys):
if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up)
{
ShowPopUpList();
listBox1.Focus();
listBox1.SelectedIndex = 0;
}
This worked just fine and dandy for me :)
ListBox lb;
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Contains("."))
{
lb = new ListBox();
lb.Location = textBox1.Location;
this.Controls.Add(lb);
lb.Items.Add("Item 1");
lb.Items.Add("Item 2");
lb.Items.Add("Item 3");
lb.Show();
}
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Down)
{
lb.Focus();
}
}
I have a simple form by which I take input:
12 Buttons, 1 Textbox (disabled & read-only)
this is what I do to handle input
Login_KeyDown() is common method I call for all the KeyDown of every UI component & the form itself..
private void Login_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
Application.Exit();
}
else if (e.KeyCode == Keys.NumPad9 || e.KeyCode == Keys.D9)
{
button3.BackgroundImage = Properties.Resources.button_hover;
button3.ForeColor = Color.White;
pin.Text = pin.Text + "9";
}
else if (e.KeyCode == Keys.Back)
{
button11.BackgroundImage = Properties.Resources.button_hover;
button11.ForeColor = Color.White;
if (pin.Text.Length > 0)
pin.Text = pin.Text.Substring(0, pin.Text.Length - 1);
}
else if (e.KeyCode == Keys.Enter)
{
MessageBox.Show(pin.Text);
}
}
This code works fine when I start the app but after I have clicked on any component, rest of the code works fine but "Enter Key Condition" doesn't work.
My guess is as "Enter Key Condition" is not working for UI components or something like that.
I have also tried using "Key Press Event" which uses KeyPressEventArgs then checking KeyChar == 13 but that is also not working.
What is the problem, and how can I solve it?
p.s.
I have not set any button click events for any button, the app is 100% KBoard based.
Check out PreviewKeyDown. Return raises that event on button controls.
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Return)
MessageBox.Show("I found return");
}
Or alternatively you can force it to raise those special keys in the KeyDown Event by using:
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Return)
e.IsInputKey = true;
}
More information: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx
Have you tried to use
Keys.Return
Instead
Edit:
Just thought of this. Do you have the acceptbutton set for the main form?
This is because your Form has AcceptButton defined. For example, you have a "OK", "Accept" or "Confirm" button with DialogResult set to "OK". This tells its parent form that there is an AcceptButton, and the Enter event on the form would go to this button.
What you should do is to catch the Enter key at form level. Add this code to the form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((this.ActiveControl == myTextBox) && (keyData == Keys.Return))
{
//do something
return true;
}
else
{
return base.ProcessCmdKey(ref msg, keyData);
}
}
I have this code for window form application and I have been attempting to convert it to a Silverlight application but it does not work!. There is a Textbox and I attached KeyDown event handler to it. when the user press the arrow key ( left or right) while the focus on the textbox, it will write . or -. When it is window form i used e.KeyCode and Keys.Right and its works great but when it is silverlight I used e.Key and key.Right and the program doesn't work good because the arrows do the 2 functions moving and write ./-. How I can work this out in Silverlight?
(My English not good)
The code ( window form):
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (sender is TextBox)
{
TextBox textBox = (TextBox)sender;
if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Right)
{
e.Handled = true;
char insert;
if (e.KeyCode == Keys.Left)
{ insert = '.'; }
else
{ insert = '-'; }
int i = textBox.SelectionStart;
textBox.Text = textBox.Text.Insert(i, insert.ToString());
textBox.Select(i + 1, 0);
}
}
}
(and Silverlight):
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (sender is TextBox)
{
TextBox textBox = (TextBox)sender;
if (e.Key == Key.Left || e.Key == Key.Right)
{
e.Handled = true;
char insert;
if (e.Key == Key.Left)
{ insert = '.'; }
else
{ insert = '-'; }
int i = textBox.SelectionStart;
textBox.Text = textBox.Text.Insert(i, insert.ToString());
textBox.Select(i + 1, 0);
}
}
}
I don't understand, is there huge different effect between using Keycode/Keys and Key/Key or because something else?
The KeyDown event will not proportionate for several keys in TextBox, as TextBox uses those keys internally and marks those as e.Handled before they get to custom user code.
Here is the MSDN quote that explains the issue further:
Another example is TextBox. Some keys
such as the ARROW keys are not
considered text by TextBox and are
instead considered specific to the
control UI behavior, and the TextBox
marks these event cases as handled.
If I were you, I'd just use the KeyUp event as your custom code does appear to work fine in that event.
Sincerely,
-- Justin Angel
You have to set
e.Handled = true;
so the event won't be consumed further down the route.