When I make C# WinForms button and textbox enabled = false color and design get gray so I need any trick or code that make textbox looks Enabled true while its Enabled = false.
For a TextBox, one way to achieve this objective is to intercept the WM_PAINT message and inspect the Enabled property. If it's false, use TextBoxRenderer class to draw the text box as if it were enabled.
Try swapping out the instances of TextBox in your designer file with this custom version:
class TextBoxEx : TextBox
{
const int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
if (m.Msg.Equals(WM_PAINT) && !Enabled)
{
paintDisabled();
return;
}
base.WndProc(ref m);
}
private void paintDisabled()
{
using (Graphics graphics = CreateGraphics())
{
TextBoxRenderer.DrawTextBox(
graphics,
Bounds,
System.Windows.Forms.VisualStyles.TextBoxState.Normal
);
}
}
}
Button
In this case, the ButtonRendererClass is used instead.
class ButtonEx : Button
{
const int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
if (m.Msg.Equals(WM_PAINT) && !Enabled)
{
paintDisabled();
return;
}
base.WndProc(ref m);
}
private void paintDisabled()
{
using (Graphics graphics = CreateGraphics())
{
ButtonRenderer.DrawButton(
graphics,
Bounds,
System.Windows.Forms.VisualStyles.PushButtonState.Normal
);
}
}
}
In Windows Forms, you can know, at any time, the current position of the cursor thanks to the Cursors class.
The same thing doesn't seem to be available for the keyboard. Is it possible to know if, for example, the Shift key is pressed?
Is it absolutely necessary to track down every keyboard notification (KeyDown and KeyUp events)?
if ((Control.ModifierKeys & Keys.Shift) != 0)
This will also be true if Ctrl+Shift is down. If you want to check whether Shift alone is pressed,
if (Control.ModifierKeys == Keys.Shift)
If you're in a class that inherits Control (such as a form), you can remove the Control.
The code below is how to detect almost all currently pressed keys, not just the Shift key.
private KeyMessageFilter m_filter = new KeyMessageFilter();
private void Form1_Load(object sender, EventArgs e)
{
Application.AddMessageFilter(m_filter);
}
public class KeyMessageFilter : IMessageFilter
{
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private bool m_keyPressed = false;
private Dictionary<Keys, bool> m_keyTable = new Dictionary<Keys, bool>();
public Dictionary<Keys, bool> KeyTable
{
get { return m_keyTable; }
private set { m_keyTable = value; }
}
public bool IsKeyPressed()
{
return m_keyPressed;
}
public bool IsKeyPressed(Keys k)
{
bool pressed = false;
if (KeyTable.TryGetValue(k, out pressed))
{
return pressed;
}
return false;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
KeyTable[(Keys)m.WParam] = true;
m_keyPressed = true;
}
if (m.Msg == WM_KEYUP)
{
KeyTable[(Keys)m.WParam] = false;
m_keyPressed = false;
}
return false;
}
}
You can also look at the following if you use WPF or reference System.Windows.Input
if (Keyboard.Modifiers == ModifierKeys.Shift)
The Keyboard namespace can also be used to check the pressed state of other keys with Keyboard.IsKeyDown(Key), or if you are subscribing to a KeyDownEvent or similar event, the event arguments carry a list of currently pressed keys.
Most of these answers are either far too complicated or don't seem to work for me (e.g. System.Windows.Input doesn't seem to exist). Then I found some sample code which works fine:
http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state
In case the page disappears in the future I am posting the relevant source code below:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace MouseKeyboardStateTest
{
public abstract class Keyboard
{
[Flags]
private enum KeyStates
{
None = 0,
Down = 1,
Toggled = 2
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern short GetKeyState(int keyCode);
private static KeyStates GetKeyState(Keys key)
{
KeyStates state = KeyStates.None;
short retVal = GetKeyState((int)key);
//If the high-order bit is 1, the key is down
//otherwise, it is up.
if ((retVal & 0x8000) == 0x8000)
state |= KeyStates.Down;
//If the low-order bit is 1, the key is toggled.
if ((retVal & 1) == 1)
state |= KeyStates.Toggled;
return state;
}
public static bool IsKeyDown(Keys key)
{
return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
}
public static bool IsKeyToggled(Keys key)
{
return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
}
}
}
Since .NET Framework version 3.0, it is possible to use the Keyboard.IsKeyDown method from the new System.Windows.Input namespace. For instance:
if (((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
{
// CTRL + F is currently pressed
}
Even though it's part of WPF, that method works fine for WinForm applications (provided that you add references to PresentationCore.dll and WindowsBase.dll). Unfortunately, however, the 3.0 and 3.5 versions of the Keyboard.IsKeyDown method did not work for WinForm applications. Therefore, if you do want to use it in a WinForm application, you'll need to be targeting .NET Framework 4.0 or later in order for it to work.
You can P/Invoke down to the Win32 GetAsyncKeyState to test any key on the keyboard.
You can pass in values from the Keys enum (e.g. Keys.Shift) to this function, so it only requires a couple of lines of code to add it.
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
// CTRL+F pressed !
}
if (Control.ModifierKeys == Keys.Shift)
//Shift is pressed
The cursor x/y position is a property, and a keypress (like a mouse click/mousemove) is an event. Best practice is usually to let the interface be event driven. About the only time you would need the above is if you're trying to do a shift + mouseclick thing.
The best way I have found to manage keyboard input on a Windows Forms form is to process it after the keystroke and before the focused control receives the event. Microsoft maintains a built-in Form-level property named .KeyPreview to facilitate this precise thing:
public frmForm()
{
// ...
frmForm.KeyPreview = true;
// ...
}
Then the form's _KeyDown, _KeyPress, and / or _KeyUp events can be marshaled to access input events before the focused form control ever sees them, and you can apply handler logic to capture the event there or allow it to pass through to the focused form control.
Although not as structurally graceful as XAML's event-routing architecture, it makes management of form-level functions in Winforms far simpler. See the MSDN notes on KeyPreview for caveats.
if (Form.ModifierKeys == Keys.Shift)
does work for a text box if the above code is in the form's keydown event and no other control captures the keydown event for the key down.
Also one may wish stop further key processing with:
e.Handled = true;
In WinForms:
if( Form.ModifierKeys == Keys.Shift )
It sounds like a duplicate of Stack Overflow question Detect Shift key is pressed without using events in Windows Forms?.
If you need to listen to keys in any generic class what are pressed when a 'Form' Window, this is your code. It doesnt listen to global windows key events, so it cannot be used to see keys when the window is not active.
Form.cs
public partial class Form1 : Form
{
public Form1()
{
// Some other Code
// Register all Keys pressed
this.KeyPreview = true;
KeyHandler.Instance.Init();
this.KeyDown += Form1_KeyDown;
this.KeyUp += Form1_KeyUp;
// Some other Code in the constructor
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
// Fire event when a key is released
KeyHandler.Instance.FireKeyUp(sender, e);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// Fire event when a key is pressed
KeyHandler.Instance.FireKeyDown(sender, e);
}
}
KeyHandler.cs
KeyHandler is a Singleton Class and can be accessed in any other Object through Handler.Instance... Easy right.
public class KeyHandler
{
#region Singleton
private static KeyHandler instance;
private KeyHandler()
{
currentlyPressedKeys = new List<Keys>();
}
public static KeyHandler Instance
{
get
{
if (instance is null)
{
instance = new KeyHandler();
}
return instance;
}
}
#endregion Singleton
private List<Keys> currentlyPressedKeys;
public List<Keys> GetCurrentlyPressedKeys { get { return currentlyPressedKeys; } }
public void FireKeyDown(object sender, KeyEventArgs e)
{
if (!currentlyPressedKeys.Contains(e.KeyCode))
{
currentlyPressedKeys.Add(e.KeyCode);
KeyEventKeyPressed(sender, e);
}
}
public void FireKeyUp(object sender, KeyEventArgs e)
{
currentlyPressedKeys.Remove(e.KeyCode);
KeyEventKeyReleased(sender, e);
}
public event EventHandler<KeyEventArgs> KeyPressed;
protected virtual void KeyEventKeyPressed(object sender, KeyEventArgs e)
{
EventHandler<KeyEventArgs> handler = KeyPressed;
handler?.Invoke(sender, e);
}
public event EventHandler<KeyEventArgs> KeyReleased;
protected virtual void KeyEventKeyReleased(object sender, KeyEventArgs e)
{
EventHandler<KeyEventArgs> handler = KeyReleased;
handler?.Invoke(sender, e);
}
public void Init()
{
// Nothing to initialize yet
}
}
// In any other Class/Object its now possible to receive KeyEvents that are fired when the 'Form' is active. So its possible to listen to key events in any Control object or anything else. Its possible to see if e.g. multiple keys are pressed like Shift+Ctrl+Q or something like that.
public class SomeClass
{
public SomeClass()
{
KeyHandler.instance.KeyPressed += Instance_KeyPressed
KeyHandler.Instance.KeyReleased += Instance_KeyReleased;
}
public void SomeMethod()
{
if (KeyHandler.Instance.GetCurrentlyPressedKeys.Contains(Keys.ShiftKey))
{
// Do Stuff when the method has a key (e.g. Shift/Control...) pressed
}
}
private void Instance_KeyPressed(object sender, KeyEventArgs e)
{
// Any Key was pressed, do Stuff then
}
private void Instance_KeyReleased(object sender, KeyEventArgs e)
{
// Do Stuff when a Key was Released
}
}
I have the following code that has worked twice and then quit working altogether after I modified the underlying form controls. I can't see what's wrong with the code or why changing the underlying controls would matter to the form.
What do I have to do to get ProcessCmdKey to work reliably?
namespace xyz
{
public partial class DaysNHours : Form
{
public DaysNHours()
{
this.KeyPreview = true;
InitializeComponent();
}
// Detect alt-key presses directed to checkboxes and time boxes
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.F))
{
MessageBox.Show("What the Ctrl+f?");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
}
I'm working on a large C# winforms project. After explaining thousands of times to my end users that they have to press tab instead of enter in textboxes, datagrids, and wherever, I decided to add a checkbox somewhere, so users can optionally set if they want to replace enter with tab. I don't like it myself, because I think weird stuff will happen, but I'd like to try it.
The thing is that I have lots of forms, and lots of places where I would have to set a keydown event or similar. I would like to put all of this in one place, on application level. Is there a way for this?
I guess this is not possible, since some controls will expose the keydown event diverently (for example in cells of the gridview). You could iterate through all controls in a form recursively and assign the event for the basic controls though.
The event itself then could be handled in a central place
I'll advice you to create a separate class that the constructor accept the parameters you need (like the textbox), You create global variables and assign the parameters to the variables in the constructor.
Then Create the event handler in the class and then you can put your code in the event handler using the variables.
You can then call the class wherever you need the keydown event
Form level (you can implement the behaviour in the base form and inherit from it):
this.KeyPreview = true;
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
PressedEnter();
base.OnKeyDown(e);
}
private bool PressedEnter()
{
bool res = false; // true if handled
Control ctr = GetFocusedControl();
if (ctr != null && ctr is TextBox)
{
res = this.SelectNextControl(ctr, true, true, true, true);
}
return res;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr GetFocus();
private Control GetFocusedControl()
{
Control focusedControl = null;
IntPtr focusedHandle = GetFocus();
if (focusedHandle != IntPtr.Zero)
// if control is not a .Net control will return null
focusedControl = Control.FromHandle(focusedHandle);
return focusedControl;
}
It probably can be done on application level too: In your main form you'll have to prefilter messages from the message loop (using message filter: Application.AddMessageFilter(your filter)), check for message WM_KEYDOWN = 0x100, check if the pressed key was ENTER, then handle it same as above.You do it only once, in your main form, it'll work on all your child forms.
In your main form class:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.mouseMessageFilter = new MouseMoveMessageFilter();
this.mouseMessageFilter.TargetForm = this;
Application.AddMessageFilter(this.mouseMessageFilter);
}
protected override void OnClosed(EventArgs e)
{
Application.RemoveMessageFilter(this.mouseMessageFilter);
base.OnClosed(e);
}
private class MouseMoveMessageFilter : IMessageFilter
{
public FormMain TargetForm { get; set; }
public bool PreFilterMessage(ref Message m)
{
if (TargetForm.IsDisposed) return false;
int numMsg = m.Msg;
int VK_RETURN=0x0D;
if (m.Msg == 0x100 &&(int)m.WParam == VK_RETURN) // WM_KEYDOWN and enter pressed
{
if (TargetForm.PressedEnter()) return true;
}
return false;
}
}
sources:
https://stackoverflow.com/a/435510/891715
http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
http://www.autohotkey.com/docs/misc/SendMessageList.htm
It's much simpler to use a MessageFilter in combination with SendKeys:
public partial class Form1 : Form, IMessageFilter
{
public Form1()
{
InitializeComponent();
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x100)//WM_KEYDOWN
{
if (m.WParam.ToInt32() == 0xd)//VK_RETURN = 0xd
{
SendKeys.Send("{TAB}");
return true; //Discard the Enter key
}
}
return false;
}
}
I use DataGridView, and in some places I add control to it (e.g. textbox, combobox)
dataGridView1.Controls.Add(comboBox);
comboBox.Focus();
The problem is that using this control, and than commiting choice by using ENTER cause the DataGridView to "handle" the key -> after clickng enter instead of choosing sth from combobox, the selection in datagridview changes( moves to next cell).
I use sth like :
public class MyDataGridView:DataGridView
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == Keys.Enter)
{
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
But it cause that datagridview and combobox doesn't answer to ENTER, and other keys...
Additional infromation: I must use ComboBox class, instead of DataGridViewCombobox. Can anyone help me how to handle ENTER in my comobox?
Try:
if((keyData == Keys.Enter) && (MyComboBox.Focused))
so DataGridView responds to ENTER except when your control is focused.
I am not sure the following code fits your situation, but maybe you could try something like:
public class MyDataGridView:DataGridView
{
public ComboBox MyComboBox { get; set; } //in case you had no other way to refer to it
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if((keyData == Keys.Enter) && (MyComboBox.Focused))
{
//commit choice logic
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
}
and from your form, if it needs, set the reference to your ComboBox:
dataGridView1.Controls.Add(comboBox);
dataGridView1.MyComboBox = comboBox;
comboBox.Focus();