Custom RichTextBox OnKeyDown override doesn't work - c#

I have this class inherited by RichTextBox. I overrided void OnKeyDown to check for incoming Tabs, because I don't want them.
Using breakpoints, I see that the overrided void is called, but it doesn't do its job.
Here is the code:
class ProgrammingTextBox : RichTextBox
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Tab)
{
// Tab was pressed, replace it with space
e.SuppressKeyPress = true; // Don't press Tab
for (int i = 0; i < 4; i++)
{
base.OnKeyDown(new KeyEventArgs(Keys.Space); // Repeat space 4 times
}
}
else base.OnKeyDown(e);
}
}
The wanted output should be text with 4 spaces but results as a Tab, like the OnKeyDown call from the for loop wasn't called.
Any idea what should I do?

base.OnKeyDown(new KeyEventArgs(Keys.Space);
OnKeyDown() on OnKeyPress() only generates notifications, their job is not to modify the Text property. That's up to you, assign the SelectedText property. Like this:
class ProgrammingTextBox : RichTextBox {
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Tab) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyCode == Keys.Tab) {
const string tabtospaces = " ";
var hassel = this.SelectionLength > 0;
this.SelectedText = tabtospaces;
if (!hassel) this.SelectionStart += tabtospaces.Length;
e.SuppressKeyPress = true;
}
else base.OnKeyDown(e);
}
}

When working with Tab (which is not an ordinary key - it can, say, be preprocessed and move focus control) you have to override a different method, ProcessCmdKey:
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.processcmdkey(v=vs.110).aspx
Something like this
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Tab) {
//TODO: Your code here
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
see also
https://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.acceptstab.aspx

Related

DataGridView TextBox cell Editing, Change Enter Key to Act Like Tab

I am re-asking this question as I now have some code to go with my issue (I deleted the old Question).
Basically when the enter key is pressed while editing a textbox cell, I would like it to act like a Tab press (Next Column in current Row Instead of Next row same column).
My problem is most of what I have tried so far doesn't work, This was my current attempted solution however.
This code is supposed to change which cell is being edited/Selected.
private void PreTranslateDGV_KeyPressEvent(object sender, KeyEventArgs e)
{
DataGridViewTextBoxEditingControl a = (DataGridViewTextBoxEditingControl) sender;
//a.PreviewKeyDown -= PreviewKeyDownEventHandler (dataGridView1_PreviewKeyDown)
MyDataGridView s = (MyDataGridView) a.EditingControlDataGridView;
if (e.KeyCode == Keys.Enter)
{
e.SuppressKeyPress = true;
int newRow;
int newColumn;
if (s.CurrentCell.ColumnIndex == s.ColumnCount - 1) // it's a last column, move to next row;
{
newRow = s.CurrentCell.RowIndex + 1;
newColumn = 0;
if (newRow == s.RowCount)
return; // ADD new row or RETURN (depends of your purposes..)
}
else // just change current column. row is same
{
newRow = s.CurrentCell.RowIndex;
newColumn = s.CurrentCell.ColumnIndex + 1;
}
s.CurrentCell = s.Rows[newRow].Cells[newColumn];
}
}
This is the code that Adds the Above event to the Cell's textbox
private void PreTranslateDGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
DataGridViewTextBoxEditingControl tb = (DataGridViewTextBoxEditingControl)e.Control;
tb.KeyDown += new KeyEventHandler (PreTranslateDGV_KeyPressEvent);
}
Most of this was code I found from StackOverflow as I have been trying to get it working for a while.
If anyone Knows how to properly Get the "Enter" Keypress from within a datagridview, While editing a cell please help.
PS: I Read on an MSDN forum (lost link) That when Editing a textbox cell, When you press enter it Stops editing. Which would explain why my code above doesn't fire On Enter, but it fires on everything else.
I am now attempting to do this by over-riding the processcmdkey
class MyDataGridView : KryptonDataGridView
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData == Keys.Enter) && (this.EditingControl != null))
{
return false;
}
//for the rest of the keys, proceed as normal
return base.ProcessCmdKey(ref msg, keyData);
}
}
But no matter what I seem to Return, the Enter key isn't passed to the KeyPressEvent.
After much, annoying trouble. Here the solution I am currently using:
private void PreTranslateDGV_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
DataGridViewTextBoxEditingControl a = (DataGridViewTextBoxEditingControl) sender;
//a.PreviewKeyDown -= PreviewKeyDownEventHandler (dataGridView1_PreviewKeyDown)
MyDataGridView s = (MyDataGridView) a.EditingControlDataGridView;
if (e.KeyCode == Keys.Enter)
{
int newRow;
int newColumn;
if (s.CurrentCell.ColumnIndex == s.ColumnCount - 1) // it's a last column, move to next row;
{
newRow = s.CurrentCell.RowIndex + 1;
newColumn = 0;
if (newRow == s.RowCount)
s.Rows.Add(1); // ADD new row or RETURN (depends of your purposes..)
}
else // just change current column. row is same
{
newRow = s.CurrentCell.RowIndex;
newColumn = s.CurrentCell.ColumnIndex + 1;
}
s.CurrentCell = s.Rows[newRow].Cells[newColumn];
}
}
private void PreTranslateDGV_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
DataGridViewTextBoxEditingControl tb = (DataGridViewTextBoxEditingControl)e.Control;
tb.PreviewKeyDown -= PreTranslateDGV_PreviewKeyDown;
tb.PreviewKeyDown += PreTranslateDGV_PreviewKeyDown;
//e.Control.KeyDown += new KeyEventHandler(PreTranslateDGV_KeyPressEvent);
}
I changed the KeyPressEvent, to a PreviewKeyDown Event. Which fires before ProcessCmdKey Gets input. Using this and my modified datagridview I was able to Get the Enter key to Act like Tab, while Inside a cell.
class MyDataGridView : KryptonDataGridView
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if ((keyData == Keys.Enter) && (this.EditingControl != null))
{
return true;
}
//for the rest of the keys, proceed as normal
return base.ProcessCmdKey(ref msg, keyData);
}
}
When ProcessCmdKey is given the Enter Key, It Immediately returns "true" to state that it has been handled. which it has by the PreviewkeyDown event
Hopefully this helps other people. I'm not sure how many other ways there are to do this, But this method worked for me.
I reused the idea of inheriting from DataGridView, but attempt to directly solve the task in the ProcessCmdKey override.
class PerfectDataGridView : DataGridView {
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if ((keyData == Keys.Enter) &&
(EditingControl != null) &&
(CurrentCell.RowIndex == RowCount - 1)) {
SendKeys.Send("{TAB}");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}

Trouble with enter/return key in keyboard handler

I'm starting with C#, and I'm doing a calculator as my first project. I want a keyboard handler for my GUI that makes the same operations as the button handlers that I did before. The problem is when I get to the "enter" key. That's my void:
private void keyboardHandler(object sender, KeyPressEventArgs e){
char keyPressed = e.KeyChar;
if (keyPressed >= (char)Keys.D0 && keyPressed <= (char)Keys.D9)
{
//Some stuff
}
else if (keyPressed == (char)Keys.Back)
{
//More stuff
}
else if (keyPressed == (char)Keys.Enter || keyPressed == (char)Keys.Return)
{
this.operate();
operator = operation.START;
}
}
The problem is that if I press the enter key, it throws the handler event BUT it also press the button as if I click on it. Here's an image:
Any idea? Thanks :)
Override ProcessCmdKey handler for your form.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Enter)
{
this.operate();
operator = operation.START;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
You need to set the KeyPressEventArgs.Handled property to true.
So this tells the operating system, or normal window messaging func (WndProc) to ignore the key press as it's already been dealth with. See: https://msdn.microsoft.com/en-us/library/system.windows.forms.keypresseventargs.handled%28v=vs.110%29.aspx
So like:
private void keyboardHandler(object sender, KeyPressEventArgs e){
char keyPressed = e.KeyChar;
if (keyPressed >= (char)Keys.D0 && keyPressed <= (char)Keys.D9)
{
//Some stuff
}
else if (keyPressed == (char)Keys.Back)
{
//More stuff
}
else if (keyPressed == (char)Keys.Enter || keyPressed == (char)Keys.Return)
{
this.operate();
operator = operation.START;
e.Handled = true;
}
}

C# TextBox NewLine simulate Ctrl+Enter on KeyDownEvent

I have a TextBox (multiline) and if I press Ctrl+Enter it just makes a new line. But I would also like to do this on Shift+Enter.
I tried:
messageTextBox_KeyDown(null, new KeyEventArgs(Keys.Control | Keys.Enter));
But this is not working.
I think that I can do this:
int lastSelectionStart = messageTextBox.SelectionStart;
messageTextBox.Text = messageTextBox.Text.Insert(messageTextBox.SelectionStart, Environment.NewLine);
messageTextBox.SelectionStart = lastSelectionStart;
But I don't like this.
How can I make it so that Shift+Enter will be the same as Ctrl+Enter?
My current code:
KeyDownEvent
if (e.KeyCode == Keys.Enter)
{
e.Handled = true;
if (e.Shift)
{
}
else if (!e.Control)
{
sendButton_Click(null, null);
}
}
In KeyPress event:
if (e.KeyChar == (char)13)
{
e.Handled = true;
return;
}
This is because I want to use the Enter key alone as Send button.
Sounds to me like the real problem you are fighting is the form's AcceptButton property. You cannot fix this with the KeyDown event handler, the keystroke is processed before it ever gets to the event.
This can be fixed by overriding the form's ProcessCmdKey() method but the cleanest way is to just create your own TextBox derived control. You can override its IsInputKey() method to tell Winforms that you want to see the Ctrl+Enter key. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox. Note how you can alter the class to your convenience to make it more adept at being a chat input box.
using System;
using System.Windows.Forms;
class ChatBox : TextBox {
public ChatBox() {
this.Multiline = true;
}
protected override bool IsInputKey(Keys keyData) {
if (keyData == (Keys.Shift | Keys.Enter)) return true;
return base.IsInputKey(keyData);
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyData == (Keys.Shift | Keys.Enter)) {
int pos = this.SelectionStart;
this.SelectedText = Environment.NewLine;
this.SelectionStart = pos;
e.Handled = e.SuppressKeyPress = true;
return;
}
base.OnKeyDown(e);
}
}

Why does this code only work in one instance?

I've set my form's KeyPreview property to true.
I've added this code:
private void PlatypusScheduleForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F9)
{
tabControlPlatypi.SelectedTab = tabPageDuckBill;
}
else if (e.KeyCode == Keys.F10)
{
tabControlPlatypi.SelectedTab = tabPagePlatypus;
}
}
When I mash F10, it works as expected; mashing F9, however, does nothing.
tabPageDuckBill is the design-time/default tabPage that displays. Why would F10 work in taking me to the "other" tab page, but F9 then not go back to the original?
I found that if I just did this:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F9)
{
tabControl1.SelectedTab = tabPage1;
e.SuppressKeyPress = true;
}
else if (e.KeyCode == Keys.F10)
{
tabControl1.SelectedTab = tabPage2;
e.SuppressKeyPress = true;
}
}
it'll toggle back and forth just fine. Without that e.SuppressKeyPress = true;, however, it exhibited the behavior you mentioned.
I ran into this same problem in the past, and the problem persisted even after removing suspect code from the SelectedIndexChanged() event. I then used a different techniques that worked much better. Instead of using the form KeyDown event, I overrode the form ProcessCmdKey event as follow:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F9)
{
this.tabControl1.SelectedTab = tabPage1;
return true;
}
else if (keyData == Keys.F10)
{
this.tabControl1.SelectedTab = tabPage2;
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

How to Control Buttons via Numpad Keys in Winform?

I have this requirement that the users need to use the keyboard numpad keys to control specific button assigned to it and perform each function.
Example:
if Numpad key 0 is press then Button0 will be triggered.
Or
if(Numpad0 is pressed)
{
//do stuff
if (inputStatus)
{
txtInput.Text += btn0.Text;
}
else
{
txtInput.Text = btn0.Text;
inputStatus = true;
}
}
else if(Numpad1 is pressed)
{
//do stuff
}
In my form i have a split container then all Buttons are located on a group box.
Set KeyPreview to true and handle KeyDown:
private void Form_KeyDown(object sender, KeyDownEventArgs e) {
if(e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9)
((Button) this["Button" + (e.KeyCode - Keys.NumPad0).ToString()]).PerformClick();
}
I haven't tested it, but that's about how I would do it.
Add a window handler for the keydown event:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys./*numpad keys*/)
{
// do something such as call the click handler for your button!
e.Handled = true;
}
}
Or you can do it for the Form instead! You didn't specify, but the logic is the same.
And don't forget to turn KeyPreview on. Use Keys.NumPad0, Keys.NumPad1, etc for the number pad keys. See MSDN for the Keys Enumeration.
If you want to prevent the keys default action being performed set e.Handled = true as shown above.
Set the Form's KeyPreview to true and handle the Form.KeyDown event.
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.NumPad0)
{
Button0.PerformClick()
e.Handled = true;
}
else if (e.KeyCode == Keys.NumPad1)
{...}
...
}
By using ProcessCmdkey Solves the Problem:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Numpad0)
{
Numpad0.PerformClick();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Thanks

Categories