C# how to trigg a key event in a tabcontrol specific tab? - c#

I have an tabControl1 in my form with three TabPages named TabPage1, TabPage2 and TabPage3.
When TabPage 2 has focus I need to raise an key event (arrow keys for navigation).
This event should not be raised in the other TabPages.
Anybody know how?

On Selected event handler you can cast the sender to the proper control and check for it's name. If the event is generated from TabPage2 you can fire the key event.
Something like this
private void TabPage_Selected(object sender, EventArgs e)
{
TabPage source = sender as TabPage;
if(source.Name.equals("TabPage2"))
//Do whatever...
}

You'll need to derive your own control from TabControl so that you can intercept the arrow keys and generate an event. 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.
using System;
using System.Windows.Forms;
class MyTabControl : TabControl {
public event EventHandler<KeyEventArgs> ArrowKeys;
protected void OnArrowKeys(KeyEventArgs e) {
EventHandler<KeyEventArgs> handler = ArrowKeys;
if (handler != null) handler(this, e);
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Up || keyData == Keys.Down || keyData == Keys.Left || keyData == Keys.Right) {
var e = new KeyEventArgs(keyData);
OnArrowKeys(e);
if (e.Handled) return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Sample usage in a form:
private void myTabControl1_ArrowKeys(object sender, KeyEventArgs e) {
if (myTabControl1.SelectedIndex == 1) {
// Do something with e.KeyData
//...
e.Handled = true;
}
}

protected override bool ProcessCmdKey(ref Message m, Keys keyData)
{
bool blnProcess = false;
if (keyData == Keys.Left)
{
blnProcess = true;
MessageBox.Show("Key left");
if (myTabControl1.SelectedIndex == 1)
MessageBox.Show("inside");
}
}
This code seems to work
So when I have selected the tabPage2 a Messagebox tells me "inside" when i press left arrow key.
Probalby not the correct thing to do thing but atleast it works for now...

I did this in VB .NET, I can post it in C# if you really need it but this should show you how to handle the catching of the event.
Public Class Form1
'give a variable as a TabPage here so we know which one is selected(in focus)
Dim selectedPage As TabPage = TabPage1
'If a key is pressed when the tab control has focus, it checks to see if it is the right tab page
'and then show a message box(for demonstration)
Private Sub TabControl1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TabControl1.KeyDown
'The IF Not is to basically catch any odd happening that might occur if a key stroke gets passed with
'no selected tab page
If Not selectedPage Is Nothing Then
'If the tabpage is TabPage2
If selectedPage.Name = "TabPage2" Then
MessageBox.Show("Key Pressed")
End If
End If
End Sub
'This handles the actual chaning of the tab pages
Private Sub TabControl1_Selected(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TabControlEventArgs) Handles TabControl1.Selected
selectedPage = TabControl1.SelectedTab
End Sub
And now you just need to use the actual key presses.
Michael Sarchet

private void Main_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.C) // I used the C Key
{
if (tabControl.SelectedIndex == 0) // control is only in tab 1 (index 0) endabled
{
// Your Code
}
}
}

A C# version of msarchet's answer:
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
public class Form1
{
// give a variable as a TabPage here so we know which one is selected(in focus)
private TabPage selectedPage = TabPage1;
// If a key is pressed when the tab control has focus, it checks to see if it is the right tab page
// and then show a message box(for demonstration)
private void TabControl1_KeyDown(System.Object sender, System.Windows.Forms.KeyEventArgs e)
{
// The IF Not is to basically catch any odd happening that might occur if a key stroke gets passed with
// no selected tab page
if (!selectedPage == null)
{
// If the tabpage is TabPage2
if (selectedPage.Name == "TabPage2")
MessageBox.Show("Key Pressed");
}
}
// This handles the actual chaning of the tab pages
private void TabControl1_Selected(System.Object sender, System.Windows.Forms.TabControlEventArgs e)
{
selectedPage = TabControl1.SelectedTab;
}
}
I hope this helps you :)

Related

how to put focus on Label and Picture Box control in windows form application? [duplicate]

I am continuing to program some kind of keyboard navigation in my simple graphic program (using C#). And I ran into trouble once again.
My problem is that I want to process the keyboard input to move a layer around. Moving the layer with the mouse already works quite well, yet the control doesn't get the focus (neither KeyUp/KeyDown/KeyPress nor GotFocus/LostFocus is triggered for this control).
Since my class derives from Panel (and overwrites a couple of events), I've also overwritten the events mentioned above, but I can't succeed in getting those events triggered.
I think I could manage to implement keyboard response either using something like Keyboard.GetState() or ProcessCmdWnd or something. However: I still have to be able to tell when the control got the focus.
Is there an more or less elegant way to add this ability to a user control (which is based on Panel)?
I've checked many threads in here and I might use this approach for keyboard input. The focus problem however still remains.
Thank you very much for information in advance!
Igor.
p.s.: I am programming in C# .NET v3.5, using VS2008. It's a Windows.Forms application, not WPF.
The Panel class was designed as container, it avoids taking the focus so a child control will always get it. You'll need some surgery to fix that. I threw in the code to get cursor key strokes in the KeyDown event as well:
using System;
using System.Drawing;
using System.Windows.Forms;
class SelectablePanel : Panel {
public SelectablePanel() {
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
protected override void OnMouseDown(MouseEventArgs e) {
this.Focus();
base.OnMouseDown(e);
}
protected override bool IsInputKey(Keys keyData) {
if (keyData == Keys.Up || keyData == Keys.Down) return true;
if (keyData == Keys.Left || keyData == Keys.Right) return true;
return base.IsInputKey(keyData);
}
protected override void OnEnter(EventArgs e) {
this.Invalidate();
base.OnEnter(e);
}
protected override void OnLeave(EventArgs e) {
this.Invalidate();
base.OnLeave(e);
}
protected override void OnPaint(PaintEventArgs pe) {
base.OnPaint(pe);
if (this.Focused) {
var rc = this.ClientRectangle;
rc.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(pe.Graphics, rc);
}
}
}
The code from Hans Passant translated to VB.NET
Imports System
Imports System.Drawing
Imports System.Windows.Forms
Public Class SelectablePanel
Inherits Panel
Public Sub New()
Me.SetStyle(ControlStyles.Selectable, True)
Me.TabStop = True
End Sub
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
Me.Focus()
MyBase.OnMouseDown(e)
End Sub
Protected Overrides Function IsInputKey(ByVal keydata As Keys) As Boolean
If (keydata = Keys.Up OrElse keydata = Keys.Down) Then Return True
If (keydata = Keys.Left OrElse keydata = Keys.Right) Then Return True
Return MyBase.IsInputKey(keydata)
End Function
Protected Overrides Sub OnEnter(ByVal e As EventArgs)
Me.Invalidate()
MyBase.OnEnter(e)
End Sub
Protected Overrides Sub OnLeave(ByVal e As EventArgs)
Me.Invalidate()
MyBase.OnLeave(e)
End Sub
Protected Overrides Sub OnPaint(ByVal pe As PaintEventArgs)
MyBase.OnPaint(pe)
If (Me.Focused) Then
Dim rc As Rectangle = Me.ClientRectangle
rc.Inflate(-2, -2)
ControlPaint.DrawFocusRectangle(pe.Graphics, rc)
End If
End Sub
End Class
call focus in click event
private void Panel_Click(object sender, EventArgs e)
{
Panel.Focus();
}
To get the focus,check for MouseEnter event in Properties window.
Write below code:
private void mainPanel_MouseEnter(object sender, EventArgs e)
{
mainPanel.Focus();
}
The simplest trick I use when for any reason I can’t use the parent Form KeyPreview property to make the Form handle key events, is to put a Textbox on
The panel:
Panel.Controls.Add(_focusTextBox = new TextBox() { Visible = true , Left = -300, TabIndex = 0});
And use it to capture KeyDown event:
_focusTextBox.KeyDown += panel_KeyDown;
The last step is to set focus to this TextBox when other controls on the panel clicked:
_focusTextBox.Focus();
Panels are not getting focus, you have to select the panel if you want to track leave and enter events
call panel1.Select() in MouseClick Event

Catch and process KeyPress/KeyDown without modifying text in TextBox

I currently have the following event handler which catches the Ctrl+Enter key combo in my Form code:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter && e.Control)
{
// Stuff
}
}
I also have two non-ReadOnly TextBoxes in the form, one of which is multiline, while the other one isn't. Whenever I hit Ctrl+Enter, the event does get handled, but it also registers as an Enter keypress when the focus is in either TextBox. What I want to do is register the key combo without the Enter keypress modifying the text in either box. Is there any way I could go about doing this?
Your best choice is use ProcessCmdKey: Just add this to your Form add it will work:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.Enter))
{
// Stuff
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
You should use the PreviewKeyDown event instead and set the IsInputKey property accordingly:
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Enter && e.Control)
{
// Stuff
e.IsInputKey = false;
}
}
UPDATE: From the name of your handler, I guess you added it to the Form's KeyPress/KeyDown/PreviewKeyDown event. Instead you should register the method I showed above with each TextBox's PreviewKeyDown event.
To not destroy what already works for you, you may leave your code as it is and just add a handler to the TextBox's PreviewKeyDown event where you set IsInputKey to false for the specified keys, but don't do your // Stuff.

How to enable a WinForm button in time to receive focus by tabbing

Visual Studio 2010, C#
I have a ComboBox with a DropDown, AutoComplete set to SuggestAppend and the AutoCompleteSource is from the ListItems. The user keys data into it until the have the correct entry. Utill the data matches one of the list items, a button next to the combobox is disabled.
If the user hits the tab key the autocomplete feature accepts current suggestion. It also moves on to the next control in tab sequence that is enabled. Of course since I want it to go to the disbabled button I need to enable it as soon as I validate the entry.
The problem is that none of the events I've tried, PreviewKeyDown, LostFocus, SelectedIndexChanged allow me to enable the button in time for it to be proccessed and receive the focus. It always goes to the next button in tab order which is always enabled.
I am about ready to leave the button enabled and have it give an error if pressed too soon but I don't want to do it that way. I also don't want to get into have special mode flags to keep track of when these controls receive focus. Validation seems to be a normal thing, but I'm stuck.
If the SelectedIndexChanged worked when the user made a match this would be easy. It doesn't fire when the box clears nor when a typed match is found.
You could create your own ComboBox class to encapsulate this behavior. Something like this:
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.myComboBox1.TheButton = this.button1;
this.myComboBox1.Items.AddRange( new string[] {
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"
} );
button1.Enabled = false;
}
}
public class MyComboBox : ComboBox
{
public Control TheButton { get; set; }
public MyComboBox()
{
}
bool IsValidItemSelected
{
get { return null != this.SelectedItem; }
}
protected override void OnValidated( EventArgs e )
{
if ( null != TheButton )
{
TheButton.Enabled = this.IsValidItemSelected;
TheButton.Focus();
}
base.OnValidated( e );
}
protected override void OnTextChanged( EventArgs e )
{
if ( null != TheButton )
{
TheButton.Enabled = this.IsValidItemSelected;
}
base.OnTextChanged( e );
}
}
}
try this :
key_press event :
if (e.KeyData == Keys.Enter)
{
button2.Enabled = true;
button2.Focus();
}
Instead of the event hanlders you mentioned, (LostFocus, SelectedIndexChanged and PreviewKeyDown) use the "Validated" event of your combobox to set the enabled state of the button.
You may need to also manually focus on the button to force the focus to move to it though.
e.g.
private void comboBox1_Validated(object sender, EventArgs e)
{
button1.Enabled = true;
button1.Focus();
}
With some thought to the other answers here I came up with a partial senario that works without using AutoComplete. A side effect is that the PreviewKeyDown event is called a second time and therefore validation is called twice. I wonder why... maybe I should ask another question.
private void comboBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) {
if (e.KeyData == Keys.Tab) {
if (ValidationRoutine()) {
e.IsInputKey = true; //If Validated, signals KeyDown to examine this key
} //Side effect - This event is called twice when IsInputKey is set to true
}
}
private void comboBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData == Keys.Tab) {
e.SuppressKeyPress = true; //Stops further processing of the TAB key
btnEdit.Enabled = true;
btnEdit.Focus();
}
}
Once you turn on AutoCompleteMode with any setting other than None, the KeyDown event doesn't fire for Tab anymore the key is silently eaten.

DataGridView keydown event not working in C#

DataGridView keydown event is not working when I am editing text inside a cell.
I am assigning shortcut Alt+S to save the data, it works when cell is not in edit mode, but if it is in edit mode below code is not working
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Alt | Keys.S))
{
//save data
}
}
Whenever a cell is in edit mode, its hosted control is receiving the KeyDown event instead of the parent DataGridView that contains it. That's why your keyboard shortcut is working whenever a cell is not in edit mode (even if it is selected), because your DataGridView control itself receives the KeyDown event. However, when you are in edit mode, the edit control contained by the cell is receiving the event, and nothing happens because it doesn't have your custom handler routine attached to it.
I have spent way too much time tweaking the standard DataGridView control to handle edit commits the way I want it to, and I found that the easiest way to get around this phenomenon is by subclassing the existing DataGridView control and overriding its ProcessCmdKey function. Whatever custom code that you put in here will run whenever a key is pressed on top of the DataGridView, regardless of whether or not it is in edit mode.
For example, you could do something like this:
class MyDataGridView : System.Windows.Forms.DataGridView
{
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
{
MessageBox.Show("Key Press Detected");
if ((keyData == (Keys.Alt | Keys.S)))
{
//Save data
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Also see related, though somewhat older, article: How to trap keystrokes in controls by using Visual C#
Another way of doing it is by using the EditingControlShowing event to redirect the event handling to a custom event handler as below:
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is DataGridViewTextBoxEditingControl tb)
{
tb.KeyDown -= dataGridView1_KeyDown;
tb.KeyDown += dataGridView1_KeyDown;
}
}
//then in your keydown event handler, execute your code
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Alt | Keys.S))
{
//save data
}
}
This is true that EditingControlShowing can help, but not if you wants to catch the Enter key. In that case, one should use the following method:
private void dataGridView_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (e.Control is DataGridViewTextBoxEditingControl)
{
DataGridViewTextBoxEditingControl tb = e.Control as DataGridViewTextBoxEditingControl;
tb.KeyDown -= dataGridView_KeyDown;
tb.PreviewKeyDown -= dataGridView_PreviewKeyDown;
tb.KeyDown += dataGridView_KeyDown;
tb.PreviewKeyDown += dataGridView_PreviewKeyDown;
}
}
void dataGridView_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyData == Keys.Enter)
{
<your logic goes here>
}
}
A simpler way I just tried out is as follows:
Set the KeyPreview property of the Form to true.
Instead of catching the KeyDown event on Grid, catch the KeyDown event on Form.
Code as follows:
Private Sub form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If grd.Focused Then
'Do your work
End If
End Sub
I worked with this
private void grdViewOrderDetail_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
grdViewOrderDetail_KeyDown(null,null);
}
private void grdViewOrderDetail_KeyDown(object sender, KeyEventArgs e)
{
//Code
}
The solution
class MyDataGridView : System.Windows.Forms.DataGridView {
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData) {
if ( keyData == Keys.Enter ) {
.
Process Enter Key
.
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
Worked perfectly for me
use PreviewKeyDown event
private void dataGridView1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
}

C# trying to capture the KeyDown event on a form

I am creating a small game, the game is printed onto a panel on a windows form. Now i want to capture the keydown event to see if its the arrow keys that has been pressed, the problem however is that i can't seem to capture it.
Let me explain, on the form i have 4 buttons and various other controls and if the user for instance press one of the buttons (to trigger a game event) then the button has focus and i can't capture the movements with the arrow keys.
I tried something like
private void KeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Left)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.E);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Right)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.W);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Up)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.N);
game.DrawObjects(panel1.CreateGraphics());
}
else if (e.KeyCode == Keys.Down)
{
game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.S);
game.DrawObjects(panel1.CreateGraphics());
}
}
and then when the form key down event was pressed, i used this
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
KeyDown(e);
}
I also added keydown for the buttons and the various other controls on the windows form, but i am not getting any response back. I have setup a breakpoint inside the function to see if it's being called, but that breakpoint never triggers?
Any ideas?
The most optimal was to have a general KeyDown event that triggers (regardless of what control that currently has focus) and then calls the KeyDown method.
Have you set the KeyPreview property of the form to true? That will cause the form to get a "first look" at key events.
Update: getting this to work properly when a Button has focus seems to be a bit tricky. The Button control intercepts the arrow key presses and moves focus to the next or previous control in the tab order in a manner so that the KeyDown, KeyUp and KeyPress events are not raised. However, the PreviewKeyDown event is raised, so that can be used:
private void Form_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = ProcessKeyDown(e.KeyCode);
}
// event handler for the PreViewKeyDown event for the buttons
private void ArrowButton_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
ProcessKeyDown(e.KeyCode);
}
private bool ProcessKeyDown(Keys keyCode)
{
switch (keyCode)
{
case Keys.Up:
{
// act on up arrow
return true;
}
case Keys.Down:
{
// act on down arrow
return true;
}
case Keys.Left:
{
// act on left arrow
return true;
}
case Keys.Right:
{
// act on right arrow
return true;
}
}
return false;
}
Still, the focus moves around in a rather ugly manner...
I believe the easiest way of solving this problem is through overriding the ProcessCmdKey() method of the form. That way, your key handling logic gets executed no matter what control has focus at the time of keypress. Beside that, you even get to choose whether the focused control gets the key after you processed it (return false) or not (return true).
Your little game example could be rewritten like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Left)
{
MoveLeft(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Right)
{
MoveRight(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Up)
{
MoveUp(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else if (keyData == Keys.Down)
{
MoveDown(); DrawGame(); DoWhatever();
return true; //for the active control to see the keypress, return false
}
else
return base.ProcessCmdKey(ref msg, keyData);
}
Override IsInputKey behaviour
You must override the IsInputKey behavior to inform that you want the Right Arrow key to be treated as an InputKey and not as a special behavior key.
For that you must override the method for each of your controls.
I would advise you to create your won Buttons, let's say MyButton
The class below creates a custom Button that overrides the IsInputKey method so that the right arrow key is not treated as a special key. From there you can easily make it for the other arrow keys or anything else.
public partial class MyButton : Button
{
protected override bool IsInputKey(Keys keyData)
{
if (keyData == Keys.Right)
{
return true;
}
else
{
return base.IsInputKey(keyData);
}
}
}
Afterwards, you can treat your keyDown event event in each different Button or in the form itself:
In the Buttons' KeyDown Method try to set these properties:
private void myButton1_KeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
//DoSomething();
}
-- OR --
handle the common behaviour in the form: (do not set e.Handled = true; in the buttons)
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//DoSomething();
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
KeyPreview = true;
KeyDown += new KeyEventHandler(Form1_KeyDown);
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
System.Diagnostics.Debug.Write(e.KeyCode);
}
}

Categories

Resources