Focus through TextBoxes with arrows keys in C# - c#

I have many textboxes on this form; how can I use arrow keys to focusing one by one?
Or how can I make the code below more easy and readable?
This code is basic and use for limited textboxes I think but I can't rewrite the same lines into each textbox.
40 is for Down key, 38 is for up key
my form picture, please see it
private void t1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyValue == 40) { t1a.Focus(); }
if (e.KeyValue == 38) { t1c.Focus(); }
}
private void t1a_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyValue == 40) { t1b.Focus(); }
if (e.KeyValue == 38) { t1.Focus(); }
}
private void t1b_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyValue == 40) { t1c.Focus(); }
if (e.KeyValue == 38) { t1a.Focus(); }
}
private void t1c_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyValue == 40) { t1.Focus(); }
if (e.KeyValue == 38) { t1b.Focus(); }
}

An idea I have would be:
You have a variable (int counter = 0;) and a list of TextBoxes (List<TextBox> textBoxes = new();). In the list, there are all the TextBoxes you use, arranged in the order you want them to be clicked through.
For example:
private void PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyValue == 40) { counter--; }
else if (e.KeyValue == 38) { counter++; }
textBoxes[counter].Focus();
}
The idea is that the integer counter represents the index of the TextBox in the list textBoxes which currently has the focus. When clicking the buttons, it changes the focused TextBox through the variable counter and gets its focus.
Note that this event-method has to be assigned to all the TextBoxes!
Hope it's what you're looking for and it helps you!

Another way is to catch the pressed key directly from the FORM.
To do this you must enable the KeyPreview property. More info here enter link description here
You can use:
void MainFormLoad(object sender, EventArgs e)
{
this.KeyPreview=true;
}
Then:
void MainFormKeyDown(object sender, KeyEventArgs e)
{
// Make a list of textBoxes
List<string> mylist = new List<string>(new string[] { "t1", "t1a" , "t1b", "t1c"});
//Get the name of CurrentTextBox
string CurrentTextBox=ActiveControl.Name;
//Get the index of the CurrentTextBox in textBoxes list
int index= mylist.IndexOf(CurrentTextBox);
//Check the KeyCode and walk throught the list: {"t1", "t1a" , "t1b", "t1c"}.
//if the value of "index" is be negative or over range we will rearrange it.
if (e.KeyCode.ToString()=="Up") index--; if (index < 0) index=mylist.Count-1;
if (e.KeyCode.ToString()=="Down") index++; if (index >= mylist.Count) index=0;
//Set the desired textbox to be focused.
Controls[mylist[index]].Focus();
}

Related

Is there a way to handle all the number buttons in one keyboard event instead of doing for each buttons in a calculator?

Instead of copying and pasting for each number is there a method that could reference to all buttons?
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.D5)
{
Five.PerformClick();
}
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if(e.KeyCode == Keys.D5)
{
Five.PerformClick();
}
}
Firstly, the enum values Keys.D0 to Keys.D9 have sequential integer values. You can abuse this knowledge to turn the KeyCode directly into an array index.
var buttons = new Button[] {Zero, One, ... etc ...};
if(e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9){
var index = (int)e.KeyCode - (int)Keys.D0;
var button = buttons[index];
button.PerformClick();
}
if(e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9){
// similar to the above
}
Or you could rearrange your code. Create a separate method for doing the work of "user entered a digit". Then call that method from both the button click event and form key event.
private void HandleDigit(int value){
// todo
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9){
var value = (int)e.KeyCode - (int)Keys.D0;
HandleDigit(value);
}
}
Maybe this can give you an idea -- instead of the code you show something like
Button.PerformClick('5');
would do what you want. Or even
Button.PerformNumberClick(5);
and if + is preseed
Button.PerformOperatorClick('+');
You can create and event for the first button and then tie all the calculator buttons to that event, inside the event you know what key (number) is pressed.
Here is a code that could be useful, i only added two buttons to test it and notice when i live the form im releasing handles unsubscribing the events:
using System;
using System.Windows.Forms;
namespace Calculator
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
CmdButton1.KeyDown += CmdButtonKeyDown;
CmdButton2.KeyDown += CmdButtonKeyDown;
}
private void CmdButtonKeyDown(object sender, KeyEventArgs e)
{
if(e.KeyCode==Keys.NumPad1 || e.KeyCode == Keys.NumPad2 )
MessageBox.Show("KeyPressed is " + e.KeyCode.ToString());
}
private void Form1_Leave(object sender, EventArgs e)
{
CmdButton1.KeyDown -= CmdButtonKeyDown;
CmdButton2.KeyDown -= CmdButtonKeyDown;
}
}
}

C# - txtbox.Undo() not working as expected for Del key

I'm making a Notepad variant in Visual Studio (Winform, C#). It has a toolstrip, with options such as Undo, Cut, Copy, Paste, Delete, etc. The shortcut keys are enabled and connected with the menu options (CTRL + Z, CTRL + C, etc).
The rest of the Notepad variant is filled with a multiline textbox.
The problem arises when I want to delete the text from the textbox via the Delete key, or the menu option - while that works (i.e. the characters to the right of the current caret position are deleted, selected characters are deleted, etc), I am unable to undo that specific action.
This is the relevant part of my code:
private void mnuCut_Click(object sender, EventArgs e)
{
if(txtbox.SelectedText != "")
{
txtbox.Cut();
}
}
private void mnuCopy_Click(object sender, EventArgs e)
{
if (txtbox.SelectedText != "")
{
txtbox.Copy();
}
}
private void mnuPaste_Click(object sender, EventArgs e)
{
if(Clipboard.GetDataObject().GetDataPresent(DataFormats.Text) == true)
{
if(txtbox.SelectionLength > 0)
{
txtbox.SelectionStart = txtbox.SelectionStart + txtbox.SelectionLength;
}
txtbox.Paste();
}
}
private void mnuUndo_Click(object sender, EventArgs e)
{
if(txtbox.CanUndo == true)
{
txtbox.Undo();
txtbox.ClearUndo();
}
}
private void txtbox_KeyUp(object sender, KeyEventArgs e)
{
// Delete
if(e.KeyCode == Keys.Delete)
{
if(txtbox.SelectionLength < 1)
{
txtbox.SelectionLength = 1;
}
txtbox.SelectedText = "";
}
// Select all
if(e.Modifiers == Keys.ControlKey && e.KeyCode == Keys.A)
{
txtbox.SelectAll();
}
}
private void mnuDelete_Click(object sender, EventArgs e)
{
if (txtbox.SelectionLength < 1)
{
txtbox.SelectionLength = 1;
}
txtbox.SelectedText = "";
}
private void selectAllToolStripMenuItem_Click(object sender, EventArgs e)
{
txtbox.SelectAll();
}
I think the problem may be in the way I'm deleting characters with the mnuDelete_Click and KeyUp event handlers. The same thing happens if I replace txtbox.SelectedText = "" with txtbox.SelectedText = String.Empty.
I know that I might be better off by using, say, txtbox.Cut(), like this:
private void txtbox_KeyUp(object sender, KeyEventArgs e)
{
// Delete
if(e.KeyCode == Keys.Delete)
{
if(txtbox.SelectionLength < 1)
{
txtbox.SelectionLength = 1;
}
//txtbox.SelectedText = "";
txtbox.Cut();
}
// Select all
if(e.Modifiers == Keys.ControlKey && e.KeyCode == Keys.A)
{
txtbox.SelectAll();
}
}
private void mnuDelete_Click(object sender, EventArgs e)
{
if (txtbox.SelectionLength < 1)
{
txtbox.SelectionLength = 1;
}
//txtbox.SelectedText = "";
txtbox.Cut();
}
But, even though this works, it'll replace the current contents of the clipboard with whatever was deleted / cut, which is something I don't want.
Finally, I ended up using SendKeys.Send("{BACKSPACE}"), and that gave the desired functionality. But the solution doesn't feel right - the original action was pressing the Delete key, not the Backspace key.
So, my question is this - how can delete characters via the Delete key, and obtain the ability to undo it, without resorting to hacky solutions? Or does it make no difference in the end, because it works as it is?

Enter key in C#

I have a code like below
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
if (!textBox1.AcceptsReturn)
{
button1.PerformClick();
}
}
}
After I hit Enter, it'll send a message to another textbox and begin a new line. Can anyone help me to bring the cursor back to its first line?
I tried textBox1.SelectionStart, SelectionLength and Focus but it doesn't work, is there any another way?
You can prevent that the keypress is passed on to the control by setting the KeyPressEventArgs.Handled property to true:
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == 13)
{
if (!textBox1.AcceptsReturn)
{
button1.PerformClick();
e.Handled = true;
}
}
}
As you mentioned in a comment that you are implementing a chat app, you also might want to implement the typical behavior of Shift+Return inserting a new line:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyValue == 13 && !e.Shift)
{
if (!textBox1.AcceptsReturn && !string.IsNullOrEmpty(textBox1.Text))
{
button1.PerformClick();
textBox1.Text = "";
e.Handled = true;
}
}
}
To set cursor position to the beginning of a textbox, use the following...
I will hazard a guess that you didn't use these in combination with each other...
textBox1.SelectionStart = 0;
textBox1.SelectionLength = 0;

second column of grid view accept only numbers in c# windows forms

I have a grid view..in my second column of grid view i want to enter only numerics
so i given code like this:
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex == 2)
{
int i;
if (!int.TryParse(Convert.ToString(e.FormattedValue), out i))
{
e.Cancel = true;
label1.Text ="please enter numeric";
}
else
{
}
}
}
but before doing this i want to check wethar this column contains any value or not? if any value contains then only i want to check wethar this value is numeric or not? how i can do this?
any help is very appreciable?
Simply check for a blank string first, so something like:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex == 1)
{
int i;
if (!string.IsNullOrEmpty(e.FormattedValue) && !int.TryParse(Convert.ToString(e.FormattedValue), out i))
{
e.Cancel = true;
label1.Text ="please enter numeric";
}
else
{
}
}
}

How to stop the first character in a text box from being '.'?

This is the code I currently have:
private void textBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar) && e.KeyChar != '.';
if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -1) e.Handled = true;
}
KeyPress isn't good enough to do this kind of validation. A simple way to bypass it is to paste text into the text box with Ctrl+V. Or the context menu, no key event at all.
In this specific case, the TextChanged event will get the job done:
private void textBox_TextChanged(object sender, EventArgs e) {
var box = (TextBox)sender;
if (box.Text.StartsWith(".")) box.Text = "";
}
But there's a lot more to validating numeric values. You also need to reject stuff like 1.1.1 or 1.-2 etcetera. Use the Validating event instead. Drop an ErrorProvider on the form and implement the event like this:
private void textBox_Validating(object sender, CancelEventArgs e) {
var box = (TextBox)sender;
decimal value;
if (decimal.TryParse(box.Text, out value)) errorProvider1.SetError(box, "");
else {
e.Cancel = true;
box.SelectAll();
errorProvider1.SetError(box, "Invalid number");
}
}
You probably want to use the TextChanged event, since the user could paste in values. For the best experience given the requirements, I'd suggest simply removing any leading . characters.
void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.StartsWith("."))
{
textBox1.Text = new string(textBox1.Text.SkipWhile(c => c == '.').ToArray());
}
}
This does not address a requirement to use only digits -- wasn't clear in the question if that is the case.
This works for copy and pasting too.
private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
int decimalCount=0;
string rebuildText="";
for(int i=0; i<textBox1.Text.Length; i++)
{
if (textBox1.Text[i] == '.')
{
if (i == 0) break;
if (decimalCount == 0)
rebuildText += textBox1.Text[i];
decimalCount++;
}
else if ("0123456789".Contains(textBox1.Text[i]))
rebuildText += textBox1.Text[i];
}
textBox1.Text = rebuildText;
textBox1.SelectionStart = textBox1.Text.Length;
}
You can try this:
private void TextBox_TextChanged(object sender, EventArgs e)
{
TextBox.Text = TextBox.Text.TrimStart('.');
}

Categories