In Main Form i have Short Cut Keys(ctrl + S ) for saving the data in DataBase. For combobox (ctrl + Alphabets) is the default Operation. How can I disable shortcut keys for Combobox?
UPDATE:
On keyPress event we can Do this
if (ModifierKeys == Keys.Control)
{
e.Handled = true;
}
You can try overriding ProcessCmdKey method of the Main Form:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
const int WM_KEYDOWN = 0x100;
if (keyData == (Keys.Control | Keys.S)) {
if (msg.Msg == WM_KEYDOWN)
MySaveDataToDatabase(); // <- Do your save command
return true; // <- Stop processing the WM_KeyDown message for Ctrl + S (and shortcut as well)
}
// All other key messages process as usual
return base.ProcessCmdKey(ref msg, keyData);
}
I get the feeling that your problem is actually that the combobox is getting keypresses before your form. Be sure to set the Form's KeyPreview property to true if you want to handle keypresses before your controls.
More information about the KeyPreview property:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview(v=vs.100).aspx
If you are getting issues like overriding the F4 key (which in a combobox shows all options available by default), note the bit about setting the KeyPressEventArgs.Handled property in the form's KeyPress event handler to true.
For most hot keys you can override the PreviewKeyDown event specify what to allow or not, eg:
void comboBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
var keysToIgnore = new []{
Keys.S,
Keys.X,
Keys.F4,
Keys.Space,
}.ToList();
if (keysToIgnore.Contains(e.KeyCode)) {
if(e.Modifiers == Keys.Alt) ; // Do stuff (or don't) here
}
}
There's all sorts of ways you can structure your logic depending on what your actual use case is but hopefully you get the idea.
You might find some hot key combinations aren't possible to disable this way, in which case you'll need to use the Win32API: UnregisterHotKey. More info here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646327%28v=vs.85%29.aspx
The main advantage of using the PreviewKeyDown event is you can also easily replace behaviour instead of just disabling it. The main advantage of using UnregisterHotKey is it operates at a lower level and is a far more robust and reliable way of disabling hot keys.
EDIT:
If you need to get a contiguous range of values you can try something like:
int keyCode = (int) (e.KeyCode);
if(keyCode >= (int)(Keys.A) && keyCode <= (int)(Keys.Z)) { /* do stuff */ }
but again, an ideal solution really depends on the specifics of your use case. There's no generic 'right answer'.
Related
I am developing a simple Universal Windows App using C#. I have a RichEditBox and I found a weird behavior when using Control+I key combination, which for some reason inserts a Tab (is that expected?). Because I wanted the combination of keys to toggle Italic font style, I thought the best way was through the KeyDown event.
So, this is my code:
private void richbox_KeyDown(object sender, KeyRoutedEventArgs e)
{
System.Diagnostics.Debug.Write("\nKeyDown : " + e.Key.ToString());
if (e.Key == VirtualKey.Tab)
{
richbox.Document.Selection.TypeText("\t");
e.Handled = true;
}
else if (Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) == Windows.UI.Core.CoreVirtualKeyStates.Down)
{
//If Control is pressed down, check if current key is B,I,U...
System.Diagnostics.Debug.Write(" => Control is down!");
switch (e.OriginalKey)
{
case VirtualKey.B:
toogleBold();
e.Handled = true;
break;
case VirtualKey.I:
e.Handled = true;
toogleItalic();
break;
case VirtualKey.U:
toogleUnderline();
e.Handled = true;
break;
}
}
}
My problem is, the condition on the Else If is not always true when I press the Control key. I would like to understand why and what could I do to fix it.
If I run the code and I press the control key a few times, this is the output:
KeyDown : Control => Control is down!
KeyDown : Control
KeyDown : Control => Control is down!
KeyDown : Control
...
Thanks in advance :)
I tried your code and used debugger output to see what the actual state of Ctrl is in those situations:
var state = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
Debug.WriteLine(state);
What I found out is that the second time you press the key, its state is not Down, but Down|Locked, more specifically Windows.UI.Core.CoreVirtualKeyStates.Down | Windows.UI.Core.CoreVirtualKeyStates.Locked. It turns out CoreVirtualKeyStates is a flag enum and it can have multiple values at the same time. In this case you are comparing with == which means you don't get a match. You can first use the HasFlag method or bitwise AND (&) to get the right value out and then compare and you will be good to go!
That means either this:
else if ( Window.Current.CoreWindow.GetKeyState(VirtualKey.Control).
HasFlag( CoreVirtualKeyStates.Down ) )
{
//rest of the code
}
Or this:
else if (
( Window.Current.CoreWindow.GetKeyState(VirtualKey.Control) &
Windows.UI.Core.CoreVirtualKeyStates.Down )
== CoreVirtualKeyStates.Down )
{
//rest of the code
}
I have this chunk of code in my Notepad clone program, it is to track my carat location in my RichTextBox and has been working fine for me.
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
Curpos();
}
private static int EM_LINEINDEX = 0xbb;
[DllImport("user32.dll")]
extern static int SendMessage(IntPtr hwnd, int message, int wparam, int lparam);
private void Curpos()
{
{
int line, col, index;
index = richTextBox1.SelectionStart;
line = richTextBox1.GetLineFromCharIndex(index);
col = index - SendMessage(richTextBox1.Handle, EM_LINEINDEX, -1, 0);
Lblcurpos.Text = "Line: " + (++line).ToString() + ", Column:" + (++col).ToString();
}
}
It has been working perfectly for me, until i added some code so that i could close my program with the Esc Key.
Here is the code for my Esc Key:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
this.Close();
}
}
EDIT: This is where it has the problem:
index = richTextBox1.SelectionStart;
When i am doing this, i can run my program fine, type text in my RichTextBox and everything but when i press the Esc Key it says:
Cannot Access disposed object
Object name: 'RichTextBox'
Then is says:
Trouble Shooting Tips:
Make sure you have not released a resource before attempting to use this.
Get general help for this exception
Any ideas on what i can do? I tried to use the shortcut keys but it doesn't have a Esc key you can use for the shortcut. Any help with either doing a different shortcut or a fix to this problem, i would like it!!
Try:
Application.Exit();
instead of
this.Close();
From MSDN:
Application.Exit
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed. This is the code to use if you are have called Application.Run (WinForms applications), this method stops all running message loops on all threads and closes all windows of the application.
Do note that Application.Exit() is not a substitute for this.Close(). Exit() terminates the entire application, Close() just close the form.
There are better ways to avoid accidents like this. When you handle shortcut keystrokes like you did, you should always set e.Handled and e.SuppressKeyPress to true so the keystroke will be completely dismissed and not generate any additional events. Like the one that bombed your code.
By far the best way is to use the dedicated method for this in Winforms, ProcessCmdKey(). It implements true shortcut keystroke behavior, the KeyPreview property is a VB6 compatibility feature which is close but not equivalent. Make it look like this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Escape) {
this.Close();
return true; // Used, don't process any further
}
return base.ProcessCmdKey(ref msg, keyData);
}
I'm having a little trouble figuring out how to create an inherited class that extends a windows form control to always have an event handler that will handle a keypress event for each instance of that object.
I'm probably explaining this poorly. Essentially I want to extend the DatagridView class in windows forms to always have a keyPress event handler present for any instantiated object of my extended DatagridView class.
I was wondering if it's possible to have an event handler that listens for key presses and handles them with code similar to what I have written below:
private void dgvObject_KeyPress(object sender, KeyPressEventArgs e)
{
if (Char.IsLetterOrDigit(e.KeyChar))
{
//start the loop at the currently selected row in the datagridview
for (int i = dgvObject.SelectedRows[0].Index; i < dgvObject.Rows.Count; i++)
{
//will only evaluate to true when the current index has iterated above above the
//selected rows index number AND the key press event argument matches the first character of the current row
// character of the
if (i > dgvObject.SelectedRows[0].Index && dgvObject.Rows[i].Cells[1].FormattedValue
.ToString().StartsWith(e.KeyChar.ToString(), true, CultureInfo.InvariantCulture))
{
//selects current iteration as the selected row
dgvObject.Rows[i].Selected = true;
//scrolls datagridview to selected row
dgvObject.FirstDisplayedScrollingRowIndex = dgvObject.SelectedRows[0].Index;
//break out of loop as I want to select the first result that matches
break;
}
}
}
}
The code above simply selects the next row that begins with the character of whatever the keypress event has in its event argument when fired. The reason I was wondering if I could have this as an inherited handler that is always present. I figured it'd be better than explicitly creating hundreds of handlers in my windows form for each individual DatagridView object. If my thinking is wrong please feel free to correct me! Anyway thanks for any input.
I've been programming in C# for about 5 months now, still learning as I go =)
Yes, in your inherited class just override OnKeyPress, and you should remember to call base.OnKeyPress afterwards:
protected override OnKeyPress(KeyPressEventArgs e)
{
.. all your code
base.OnKeyPress(e); // to ensure external event handlers are called
}
You can catch all key presses and even combinations by overriding ProcessCmdKey:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.F))
{
//your code here
}
return base.ProcessCmdKey(ref msg, keyData);
}
What's the 'correct/best' way to pick up a keystroke combination? The keys in question are Ctrl+Alt+Q, I want the user to press them all at the same time, at which point I am going to open a window. I'm currently doing it by have an array and then catching each keystroke individually, but my results are inconsistent, especially on a particular make of Dell laptop/windows 7 combination, but that's another story.
So after spending five minutes with google, this is just a rough version after looking at the msdn, but as I stated earlier is this version (untested) the correct/best way of doing it?
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch(keyData)
{
case Keys.Control | Keys.Alt | Keys.Q:
this.Parent.Text="<CTRL> + Alt + Q Captured";
break;
}
}
return base.ProcessCmdKey(ref msg,keyData);
}
Ignore msg.Msg, only look at keyData. And return true without calling base if you use the keystroke. Which simplifies it to:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.Alt | Keys.Q)) {
this.Parent.Text="<CTRL> + Alt + Q Captured";
return true;
}
return base.ProcessCmdKey(ref msg,keyData);
}
This should probably be an override of the form's method so you don't depend on the control having the focus. You'd use this.Text instead.
Yes, that's how I would do it if I wish to listen for key events globally.
But if you are interested in keyboard inputs ONLY when your program is the focused window (in the front on Windows), you might want to use the KeyDown event:
private void textBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// your code goes here
}
According to the documentation for System.Windows.Forms.Keys, you cannot use a bitwise OR to check for key combinations. The documentation states: "For finer control, use the Win32 API functions GetKeyState, GetAsyncKeyState, or GetKeyboardState defined in user32.dll...". But it appears that Shift, Alt and Control can be used as bitwise flags.
For those who wants open a windows or make visible/invisible with the combination of three keys (with two modifiers) by the light of #Hans Passant i found finally an answer to my problem. I was beware of | operand, putting instead && operand which was not working. It can be assigned to WFA properties to Keydown
private void ShowHidden_Click(object sender, KeyEventArgs e)
{
if (e.KeyData == (Keys.Control | Keys.Alt | Keys.M) )
{
OldBisProdId.Visible = true;
OldGanProdId.Visible = true;
}
if (e.KeyData == (Keys.Control | Keys.Alt | Keys.C))
{
OldBisProdId.Visible = false;
OldGanProdId.Visible = false;
}
}
Why does this never get called ?
propertyGrid.KeyDown += new KeyEventHandler(propertyGrid_KeyDown);
private void propertyGrid_KeyDown(object sender, KeyEventArgs e)
{
PoorLittleMethod(); //Never gets called
}
This seems to be the same for Mouse event
I'veread on some forums that PGrid is tricky on raising such events as it Inherits them from Control but does not really Raise them. is that true ? If yes, how to bypass that ?
EDIT 1:
As this seems to be "regular", I find it very light from MS not to specify this explicitely on the MSDN Reference of the propertyGrid class and leave events "as is" as if they were usable, whereas they are not. Tricky things like these are at least usually specified in "notes" inside the refs.
EDIT 2:
I am presently coding a workaround. I'll be posting it soon.
The PropertyGrid's KeyDown property is marked as Browsable(false) - presumably the conclusion we can take from this is that it is not supported in an of itself but is in fact present as a side-effect of its inheritance hierarchy.
Though, interestingly enough, its EditorBrowsable attribute (which is also a designer indicator, for Intellisense and the suchlike) is set as EditorBrowsableState.Advanced - where we would expect EditorBrowsableState.Never should the former presumption be true.
Some information from MSDN forums outlines the why of this situation:
From the tool UI Spy we can see the PropertyGrid is a just a panel and it consists of three Windows Controls. Our KeyDown event should be processed by the child control table.
The structure:
-"pane" "PropertyGrid"
--"pane" "Description Pane"
--"table" "Properties Window"
--"tool bar" "ToolBar"
The suggested solution (also provided in the MSDN link) to overcoming this is to use native system calls to retrieve window/control information, subclass NativeWindow and override the WndProc method to handle the events you like, KeyDown in this case.
You can override this from subclass of PropertyGrid to get some key info from windows message
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
CSharp PropertyGrid Events
// Property grid events can’t be easily subscribed to however there is way to get at the KeyUp event without impacting operation.
// Note: The KeyDown event can be subscribed to in the same manner but the propertygrid is NOT updated with the key presses.
// This code is added in hope it may help someone else solve the problem. It is not offered as a total solution.
// First define a class variable to indicate that events have been added.
private bool m_bPropertyGridEventsAdded = false;
public GlassInfoEntryPage(ViewBase view)
: base(view)
{
InitializeComponent();
// Subscribe to SelectedGridItemChanged
m_PropertyGrid.SelectedGridItemChanged += M_PropertyGrid_SelectedGridItemChanged;
}
// Now define a SelectedGridItemChanged Event Handler
private void M_PropertyGrid_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
int nXlocation;
int nYlocation;
PropertyGrid oPropertyGrid;
Control oControl;
if (m_bPropertyGridEventsAdded == false)
{
oPropertyGrid = (PropertyGrid)sender;
// Search the Property Grid for a PropertyGridView Control so events can be added to it
for (nXlocation = 0; nXlocation < oPropertyGrid.Width; nXlocation += 10)
{
for (nYlocation = 0; nYlocation < oPropertyGrid.Height; nYlocation += 10)
{
oControl = m_glassInfoPropertyGrid.GetChildAtPoint(new Point(nXlocation, nYlocation));
if (oControl != null)
{
if (oControl.GetType().ToString() == "System.Windows.Forms.PropertyGridInternal.PropertyGridView")
{
// Add Events here
oControl.Controls[1].KeyUp += MyCode_KeyUp;
m_bPropertyGridEventsAdded = true;
break;
}
}
}
if (m_bPropertyGridEventsAdded == true)
{
break;
}
}
}
}
// Handle the events
private void MyCode_KeyUp(object sender, KeyEventArgs e)
{
}