Is there a way in Windows Form to activate the currently focused button/control with the Q key? Or override the Enter, so that pressing Q activates the currently focused control like Enter does? I want the user to be able to control the application with just the left hand on Tab and Q to cycle controls and activate them.
private void Form2_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Q)
{
e.Handled = true;
}
I already have this, but what do I need after the e.Handled to activate the current focus?
As an option you can override ProcessCmdKey and check if the key is Q then send Enter using SendKeys.Send and return true to indicate you that you processed the key:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Q)
{
SendKeys.Send("{Enter}");
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
You can limit the behavior to buttons by checking this.ActiveControl is Button if you need.
Related
I need to let the users change to "next" textbox, combobox or button in a form when the press the Enter key (they CAN'T press Tab...)
I've found a couple of solutions (set a new event for each textbox's key pressed and set focus to the next control...) but I want this to have an easy manteinance.
Is there any magic around??
I've had problems even with tab navigation in silverlight...
private void textBox3_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
if (Keyboard.Modifiers == ModifierKeys.Shift)
textBox4.Focus();
else
textBox5.Focus();
e.Handled = true;
}
}
My goal is to implement a custom Control + S key press handler to wire up to a custom save method in a winforms app.
There are several ways to accomplish this based on my R&D. First, I tried the obvious KeyPress event handler. This wasn't powerful enough to capture the key presses I need (it wasn't called on the Editor level, which is what I needed).
The second option which looks better is the protected override bool ProcessCmdKey(ref Message msg, Keys keyData) override. This works - it intercepts the CTRL key click, but apparently I need to write extra code to persist the fact the CTRL key is pressed and intercept the next key press (which would be S in my case) and then perform the custom action.
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.S | Keys.Control))
{
// This is never called
}
else if (keyData == (Keys.Menu | Keys.Alt))
{
// this is called each time I hit CTRL
}
return true;
}
ProcessCmdKey seems to be called immediately after I hit the CTRL key.
This post suggests creating a KeyTracker class that will persist the keys pressed and do what it needs to do:
Capture Key Sequence via ProcessCmdKey
Which seems like a good option, but before I dig in an implement a memento tracking pattern, does anyone have input on how else to accomplish this seemingly common feature?
Another pattern uses the GetKeyboardState API function:
Capture multiple key downs in C#
This seems interesting, though I'm not sure it will suite my needs.
[DllImport ("user32.dll")]
public static extern int GetKeyboardState( byte[] keystate );
private void Form1_KeyDown( object sender, KeyEventArgs e )
{
byte[] keys = new byte[255];
GetKeyboardState (keys);
if( keys[(int)Keys.Up] == 129 && keys[(int)Keys.Right] == 129 )
{
Console.WriteLine ("Up Arrow key and Right Arrow key down.");
}
}
Thank you for taking a look at my problem.
UPDATE
I've added three events for key handling to my DataPanel. None of these events are being picked up by VS when I set breakpoints in the events, so this is what leads me to believe that ProcessCmdKey is my best option.
If I could get these Events to work, that would be good as well:
// Ctrl + S: Save Support
this.ParentForm.KeyPreview = true;
this.KeyPress += new KeyPressEventHandler(DataPanel_KeyPress);
this.KeyDown += new KeyEventHandler(DataPanel_KeyDown);
this.PreviewKeyDown += new PreviewKeyDownEventHandler(DataPanel_PreviewKeyDown);
None of these events seem to be caught when pressing any keys:
void DataPanel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == (Keys.S | Keys.Control))
{
SessionManager.Trace.AddTrace("You Hit Save!!");
}
}
void DataPanel_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == (Keys.S | Keys.Control))
{
SessionManager.Trace.AddTrace("You Hit Save!!");
}
}
void DataPanel_KeyPress(object sender, KeyPressEventArgs e)
{
var key = e.KeyChar;
}
UPDATE
I've solved the problem by using a simple KeyUp event and the KeyPreview flag:
void ShipmentDataPanel_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
MessageBox.Show("Control + S Key Hit!");
}
}
Thank you.
Set the KeyPreview property of our form to true. The summary of this property says: "Gets or sets a value indicating whether the form will receive key events before the event is passed to the control that has focus.". Then use the KeyUp event. Unless KeyPressed it gives also information on special keys like control keys.
I solved this by doing,
if(e.KeyData==(Keys.S | Keys.Control))
Though this is a very old question, I still like to add my answer.
The OP writes that he could not use the ProcessCmdKey because it would fire as soon he hits the Control key and would not wait until he hits the S key also.
I don't have that problem, my code below works well and the Delete() method is only called when I first hit Ctrl and then S
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool bHandled = false;
// switch case is the easy way, a hash or map would be better, but more work to get set up.
switch (keyData)
{
case Keys.F5:
RefreshList("", "", false); // call my refresh method
bHandled = true;
break;
case Keys.S | Keys.Control: // call my delete method
Delete(false);
bHandled = true;
break;
default:
base.ProcessCmdKey(ref msg, keyData);
break;
}
return bHandled;
}
protected virtual void Delete(bool handled)
{
if (handled == false)
{
MessageBox.Show("delete");
}
}
I have a control that is similar to a Popup or Menu. I want to display it and when the user clicks outside the bounds of the box, have it hide itself. I've used Mouse.Capture(this, CaptureMode.SubTree) as well as re-acquired the capture the same way Menu/Popup do in OnLostMouseCapture.
When the user clicks outside the bounds of the control, I release the mouse capture in OnPreviewMouseDown. I don't set e.Handled to true. The mouse click will make it to other controls on the main UI, but not to the close button (Red X) for the window. It requires 2 clicks to close the app.
Is there a way to tell WPF to restart the mouse click, or to send a repeated mouse click event?
Here's my code. Note I renamed it to MainMenuControl - I'm not building a Menu, so Menu/MenuItem and Popup aren't options.
public class MainMenuControl : Control
{
static MainMenuControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MainMenuControl), new FrameworkPropertyMetadata(typeof(MainMenuControl)));
}
public MainMenuControl()
{
this.Loaded += new RoutedEventHandler(MainMenuControl_Loaded);
Mouse.AddPreviewMouseDownOutsideCapturedElementHandler(this, OnPreviewMouseDownOutsideCapturedElementHandler);
}
void MainMenuControl_Loaded(object sender, RoutedEventArgs e)
{
this.IsVisibleChanged += new DependencyPropertyChangedEventHandler(MainMenuControl_IsVisibleChanged);
}
void MainMenuControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.IsVisible)
{
Mouse.Capture(this, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
}
}
// I was doing this in OnPreviewMouseDown, but changing to this didn't have any effect
private void OnPreviewMouseDownOutsideCapturedElementHandler(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine("OnPreviewMouseDownOutsideCapturedElementHandler");
if (!this.IsMouseInBounds())
{
if (Mouse.Captured == this)
{
Mouse.Capture(this, CaptureMode.None);
Debug.WriteLine("Mouse.Capture released");
}
Debug.WriteLine("Close Menu");
}
}
protected override void OnLostMouseCapture(MouseEventArgs e)
{
base.OnLostMouseCapture(e);
Debug.WriteLine("OnLostMouseCapture");
MainMenuControl reference = e.Source as MainMenuControl;
if (Mouse.Captured != reference)
{
if (e.OriginalSource == reference)
{
if ((Mouse.Captured == null) || (!reference.IsAncestorOf(Mouse.Captured as DependencyObject)))
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
// if a child caused use to lose the capture, then recapture.
else if (reference.IsAncestorOf(e.OriginalSource as DependencyObject))
{
if (Mouse.Captured == null)
{
Mouse.Capture(reference, CaptureMode.SubTree);
Debug.WriteLine("Mouse.Capture");
e.Handled = true;
}
}
else
{
//TODO: Close
Debug.WriteLine("Close Menu");
}
}
}
private bool IsMouseInBounds()
{
Point point = Mouse.GetPosition(this);
Rect bounds = new Rect(0, 0, this.Width, this.Height);
return bounds.Contains(point);
}
}
The problem is that the mouse handling you are talking about is outside the WPF eventing system and part of the operating system so we're really talking about two fairly different mouse message queues that interact well enough most of the time but in these edge case we see that the interoperability is not perfect.
You could try to generate Win32 mouse messages or send your own window a close message but all those approaches are hacks. Since popups and menus exhibit exactly the same symptoms you describe, it doesn't seem like there is going to be an easy to way to accomplish what you want as you've described it.
Instead, I suggest that you consider giving up the mouse capture when the mouse leaves the north client area of the window or some other heuristic such as a specified distance from the control. I know this is probably not ideal but it might be a satisfactory compromise if you want the close button to work badly enough.
My WPF application has behaviour triggered by the functions keys (F1-F12).
My code is along these lines:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.F1:
...
case Key.F2:
...
}
}
This works for all F-keys except F10. Debugging, I find that e.Key == Key.System when the user presses F10.
In the enum definition, F10 = 99 and System = 156, so I can rule out it being a duplicate enum value (like PageDown = Next = 20).
So, how do I tell when the user presses F10?
Is it safe to check for Key.System instead? This feels a little dirty - might it be possible that Key.System would ever result from some other key being pressed? Or is there some setting somewhere that will make F10 report as Key.F10?
In addition to Yacoder's response, use the following to check for the F10 key:
case Key.System:
if (e.SystemKey == Key.F10)
{
// logic...
}
The SystemKey property will tell you which System key was pressed.
F10 launches the window menu. It's the same in all Windows apps.
It seems that Key.System is the expected value for the F10 key.
Answer with DataContext:
public partial class BankView : UserControl
{
public BankView()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(BankView_KeyDown);
}
private void BankView_KeyDown(object sender, KeyEventArgs e)
{
try
{
switch (e.Key)
{
case Key.F4:
((BankViewModel)DataContext).OpenAccount();
break;
}
}
catch (Exception ex)
{
...
}
}
This worked for me, for F1
Private Sub Window_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
If (e.Key = Key.F1) Then
ShowHelp()
End If
End Sub
I am trying to set the MaxLength property on a RichTextBox but it does not seem to work.
Any ideas what might be happening?
The fundamental problem is that the WPF RichTextBox doesn't have a MaxLength property - unlike the Windows.Forms one.
Here's an improvement on #jhony's anwser. If you catch the PreviewKeyDown event and check the length, you also need to allow the user to press Delete and BackSpace after hitting the limit.
// In constructor
this.RichTextBox.PreviewKeyDown += this.EditBox_KeyDown;
private void EditBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Delete && e.Key != Key.Back)
{
var range = new TextRange(this.RichTextBox.Document.ContentStart, this.RichTextBox.Document.ContentEnd);
if (range.Text.Length > this.MaxLength)
{
e.Handled = true;
return;
}
}
}
You should also allow the arrow keys, because you wouldn't expect them to be disabled.
To disable pasting, put this in the constructor DataObject.AddPastingHandler(this.RichTextBox, this.EditBox_Paste); and
private void EditBox_Paste(object sender, DataObjectPastingEventArgs e)
{
e.CancelCommand();
}
However, you might want to allow pasting unless it breaks the MaxLength, in which case you'll need to check the text being inserted, and the text it is replacing. At that point I decided not to implement a MaxLength in the control, but to handle it with the rest of the validation in the form.
Add this code in yout KeyDown Event.
private void rLetter_KeyDown(object sender, KeyEventArgs e)
{
TextRange tr= new TextRange(rLetter.Document.ContentStart, rLetter.Document.ContentEnd);
if (tr.Text.Length > 4000 || e.Key == Key.Space || e.Key == Key.Enter)
{
e.Handled = true;
return;
}
}
I have some problem, The bug is :
Test this code using copy and paste text max 4000.
Sorry for my English ..