I'm trying to implement a ctrl+s shortcut so my users can save their changes in the winform app i'm developing. This is the code for the shortcut:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.Control | Keys.S))
{
//Save code
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
When a user makes a bound checkbox checked I expect the bindingsource that is used for binding to have it's data table updated with this new value. When I click the save button it shows the data table has the updated value of 1. When I do ctrl+s the value shows up as 0, so nothing gets saved.
Have you considered testing the code within the if statement to make sure that it is actually being reached?
Related
I have a WinForms usercontrol (ZedGraphControl) hosted on a WindowsFormsHost WPF control, placed in a nested Grid. When I attempt to handle Ctrl+Left/Right in the WinForms control code the control looses focus, and focus moves to control in the grid cell to the Left/Right.
What may cause this, and how can the behavior be disabled?
Edit: The behavior is triggered if a DataGrid is in the grid cell to the left or right, with cells displayed that can take focus. Also if a TextBox is there, possibly any control that can take editable focus.
Sounds like something in your WPF universe is intercepting those key combinations and using them to move focus. At first, I thought it might be WPF's built-in directional keyboard navigation, but based on your edits, I think it might be something else.
Whatever is happening, you might be able to prevent it by overriding some keyboard processing behavior in WindowsFormsHost.
public class WindowsFormsHostEx : WindowsFormsHost
{
protected override bool TranslateAcceleratorCore(ref MSG msg, ModifierKeys modifiers)
{
const int vkLeft = 0x25;
const int vkRight = 0x27;
if (modifiers == ModifierKeys.Control &&
((int)msg.wParam == vkLeft || (int)msg.wParam == vkRight))
{
var m = Message.Create(msg.hwnd, msg.message, msg.wParam, msg.lParam);
this.Child?.WindowTarget?.OnMessage(ref m);
return true;
}
return base.TranslateAcceleratorCore(ref msg, modifiers);
}
}
Based on my tests, this causes the WindowsFormsHostEx to 'claim' all Ctrl+Left/Right keystrokes when the host has focus. It dispatches them to the hosted WinForms content, with WPF apparently carrying on as if the event never happened.
Ok, ill try to keep this quick and to the point.
In C# Winforms, I have a GUI window which displays a datagridview and a textbox. Basically what I want to do is, when either the Up Arrow key or Down arrow key is pressed, to send this input straight to the datagridview in order to move up and down through the list. If any other key is pressed, I want to send this input to my textbox.
I've tried over-writing the ProcessCmdKey method and setting focus based on the keyData keycode, but what happens is the first key press will only set the control focus, then, the 2nd key press will actually work on the focused control. I'd like the input to work immediately without that one key delay.
Extra details:
The GUI class is a generic class.
Hope this makes sense! I will edit if more details are needed
Thank you!
This is tricky to do, DataGridView is difficult to tinker with. It has the ProcessUpKey() and ProcessDownKey() methods but they are protected. You'd have to override the class and add public methods so you can call them. What you tried to do failed because by the time you got the keyboard message, it is already committed to the window that has the focus.
A bit of sly hackorama that will work without making big changes to your existing form is just posting the keyboard message back, but this time with the DataGridView as the target window. Paste this snippet into your form class:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (msg.HWnd != dataGridView1.Handle && (keyData == Keys.Up || keyData == Keys.Down)) {
PostMessage(dataGridView1.Handle, msg.Msg, msg.WParam, msg.LParam);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
I am Working with C# and Windows Forms and want to use Ctrl+"Oemplus" as a function key for my application. I use a German keyboard and this key is located 2 keys right of the letter P (that ist then "+"). Whenever I press this key in combination with Ctrl and the focus is on a TextBox I get a beep.
This also happens when I switch to an US keyboard layout (still using my German keyboard). This is then the ] key.
The same happens when pressing this key while in Internet Explorers address bar.
My question is:
Why does this key combination produce a beep in a TextBox.
How can I avoid the beep?
Thanks for any efforts you put on this.
Update:
I tried it on an US/Thai keyboard and get the beep as well. This happens no matter what logical keyboard layout I use (German, US, Thai).
The beep also happens in Windows Explorer in the address bar but not in the search box.
It is very unclear what you hope to happen when you press that keystroke. TextBox leaves no doubt about it, it BEEPs! because it can see that the user is trying to do something special but it doesn't know exactly what. Good reason to beep you. Solution is to implement magic, in the //.. comment in this next snippet. With the extra code to stop the beep at the end:
private void textBox1_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyData == (Keys.Control | Keys.Oemplus)) {
// Invoke magic
//...
// Magic is done now:
e.Handled = e.SuppressKeyPress = true;
}
}
What I believe is happening is that the key combination is not allowed for the Textbox, therefore you are getting the error. You can test for the Key Combination by this code( using the right bracket key in EN Windows) it is using SuppressKeyPress to prevent the Key Combination from being passed to the underlying control to prevent the beep.
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (ModifierKeys == Keys.Control)
if (e.KeyValue == 221) // You may need to determine this value for your keyboard layout.
{
textBox1.Text += " + "; // Handle the Key combination.
e.SuppressKeyPress = true; // Prevents key from being passed to underlying control
}
}
After some time I came back on this. What I found unsatisfying with the previous solution was that every TextBox would need that handling for every 'beeping' key I use for something else. Sure I could subclass the TextBox but still I would have two places to change for every key with this behavior (the handling and the beep suppression).
Actually I use Ctrl+'+' as a command key. I did this with a global keyboard hook because the action should be available on and impact all forms.
Instead I handle this now in a base form using the following code:
// Avoid beep on Ctrl+'+' in TextBox.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Keys key = keyData & Keys.KeyCode;
bool alt = keyData.HasFlag(Keys.Alt);
bool shift = keyData.HasFlag(Keys.Shift);
bool control = keyData.HasFlag(Keys.Control);
if (key == Keys.Oemplus && !shift && control && !alt)
{
// Perform the action for Ctrl+'+'
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
For me this seems the "correct" Position and way to handle a command key. The beep is gone without any additional handling and I don't have to worry if additional command keys produce a beep or not.
When the form had a menu or toolbar this would be handled automatically by the shortcut defined for the menu item. But my forms don't have a menu or toolbar.
I have found a few textboxes here and there in my program that accepts Control+A shortcut to select the entire text "by default" with "no coding".
I don't know what additional information I have to give here to enable it for all of them, as I find absolutely no difference between these textboxes. They are all simple dragged and dropped textboxes.
Note: I'm not talking about this piece of code:
if (e.Control && e.KeyCode == Keys.A)
{
textBox1.SelectAll();
}
I want selection by default... or is there anyway to change textbox property so that textboxes accept all default windows shortcuts?
Everything else (Control + Z, Control + X, Control + C, Control + V) works by default! Why not Control + A?
Update: The text boxes that accepted Ctrl+A by default were masked textboxes, not the regular one. And at that point I was with .NET 2.0. But I guess the original problem was something else, as I can see Ctrl+A working fine by default in .NET 2.0 code.
You might be looking for the ShortcutsEnabled property. Setting it to true would allow your text boxes to implement the Ctrl+A shortcut (among others). From the documentation:
Use the ShortcutsEnabled property to
enable or disable the following
shortcut key combinations:
CTRL+Z
CTRL+E
CTRL+C
CTRL+Y
CTRL+X
CTRL+BACKSPACE
CTRL+V
CTRL+DELETE
CTRL+A
SHIFT+DELETE
CTRL+L
SHIFT+INSERT
CTRL+R
However, the documentation states:
The TextBox control does not support the CTRL+A shortcut key when the Multiline property value is true.
You will probably have to use another subclass of TextBoxBase, such as RichTextBox, for that to work.
Indeed CTRL + A will not work unless you add something like this:
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && (e.KeyCode == Keys.A))
{
if (sender != null)
((TextBox)sender).SelectAll();
e.Handled = true;
}
}
This answer worked for me in a similar question (which isn't marked as accepted)
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
var keyCode = (Keys) (msg.WParam.ToInt32() &
Convert.ToInt32(Keys.KeyCode));
if ((msg.Msg == WM_KEYDOWN && keyCode == Keys.A)
&& (ModifierKeys == Keys.Control)
&& txtYourTextBox.Focused)
{
txtYourTextBox.SelectAll();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
Original Post: How can I allow ctrl+a with TextBox in winform?
Make sure that
Application.EnableVisualStyles();
is not commented out in
static void Main()
That can disable Ctrl+A
This question wants an answer that cannot be given in the form of code avoidance, as the Win32 API at the core of the other methods doesn't allow it. If other methods DO allow it, they are just writing the code for you. :)
So the real question is: What is the smallest, neatest way to do it? This worked for me:
First, there is no need to handle WM_KEYDOWN! And no need to test for the Ctrl key already down either. I know that most examples here (and CodeProject and many other places) all say there is, but it does not cure the beep that results whenever a WM_CHAR arises that is not handled.
Instead, try handling WM_CHAR and doing the Ctrl+A selection there:
LRESULT CALLBACK Edit_Prc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam){
if(msg==WM_CHAR&&wParam==1){SendMessage(hwnd,EM_SETSEL,0,-1); return 1;}
else return CallWindowProc((void*)WPA,hwnd,msg,wParam,lParam);
}
Remember to subclass the EDIT control to this Edit_Prc() using WPA=SetWindowLong(...) where WPA is the window procedure address for CallWindowProc(...)
update: I've modified the code below to reveal some additional information regarding the key that was pressed.
update #2: I've discovered the root cause of the issue: we have an HTML control (Gecko rendering engine) on our form. When that Gecko rendering engine navigates to some Flash control, suddenly ~2% of our key presses don't get through, even after we've removed the Gecko HTML control. Wahoo, I get to blame this on Flash! Now the question is, how do I fix this?
update #3: Nope, it's not Flash. It's the Gecko rendering engine. Navigating even to Google causes some keys to not come through to our app right. Hrmmm.
We have a strange case in our WinForms app where the user presses a key combination (in this case, Alt + S), and WinForms tells us some other key combo (value 262162) is pressed:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if(keyData == (Keys.S | Keys.Alt))
{
Console.WriteLine("You pressed Alt+S");
}
else if(keyData == (Keys.Menu | Keys.Alt))
{
Console.WriteLine("What the hell?"); // This sometimes gets hit when I press Alt+S
}
}
90% of the time, You pressed Alt+S will be shown. But on rare occurrances, we press Alt + S and it says, What the hell?.
Any idea what's wrong?
EDIT I've discovered the root cause of the issue! See below.
After more experimenting, I've found that if do the following, it works as expected:
this.KeyPreview = true;
this.KeyDown += KeyDownHandler;
...
private void KeyDownHandler(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.S && e.Alt)
{
// This always works.
}
}
I can't explain why the ProcessCmdKey didn't work. I wish I knew. Until then, this is an acceptable workaround.
I've discovered the issue. We have an HTML control (Gecko rendering engine) on our form. When that gecko rendering engine is shown on a form, it must be installing a hook or something that changes some key presses, causing us to receive WM_Char instead of WM_KeyDown in certain cases.
From my testing, it would appear that 262162 would be the "Alt" key.
Edit: I overrode the ProcessCmdKey and put in a break point on the "X = 1;" statement:
protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
{
int x = (int)keyData;
if (x == 262162)
x = 1;
return true;
}
It hits that breakpoint whenever I hit the Alt key.
Could it be that you are waiting too long to press the S key and an Alt key repeat is getting fired off?
EDIT2:I tried you posted code and I receive "What the Hell" the second I touch the ALT key, however if I disable this check the Alt-S always comes through. On my system this seems to be the default key code for the Alt key. I am able to ignore it and the Alt-S Will come through afterwards.
EDIT: According to the METADATA for the Keys enumeration Keys.Menu is 18. To see this hit F12 while the cursor is on the Keys Enumeration.
The documentation states that Keys.Menu is the Alt key.
http://msdn.microsoft.com/en-us/library/system.windows.forms.keys.aspx
This tells me that it is reporting the Alt key was pressed(18) with the Alt key modifier(262144) crazy stuff.
Just out of curiosity could you try this:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.S | Keys.Alt))
{
MessageBox.Show("You pressed Alt+S");
}
else if (keyData == (Keys.Menu | Keys.Alt))
{
return false;
}
return true;
}
returning false indicates that this is not a command key.