first of I'm working with WPF and i'm new to it.
I added a KeyDownEvent to a content control in xaml:
<ContentControl Grid.Row="1" Name="dockingContentControl" KeyDown="dockingContentControl_KeyDown"/>
I know, probably there is a better way to add a KeyDown event.
(Would also help)
But the event is working. So I used a simple Console.WriteLine command like so:
private void dockingContentControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
Console.WriteLine(e.Key);
}
and it showed me the buttons I pressed.
But somehow it did not trigger with the Arrowkeys.
I don't know why all other (I think all, didn't test all) buttons are working, but the Arrowkeys not.
Did I miss something or did I have to add some kind of extra code.
Commend: All other buttons are recognized, with the exception of the fn-button.
The background chart is moving, could it be that the chart has the focus and doesn't "forward" the input?
It depends what Controls you have placed inside your ContentControl and what control has the focus. Some keys like TAB, RETURN, ESC, and arrow keys, are typically ignored by some controls because they are not considered input key presses. The arrow keys are considered navigation keys and pressing these keys typically do not raise the KeyDown (for a Button as an example)
You can try to use the PreviewKeyDown-Event for this case.
If I use your provided code in a minimal solution I receive the KeyDown-Events for all keys, but it is required that the ContentControl has the focus.
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
dockingContentControl.Focus();
}
private void dockingContentControl_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
Console.WriteLine(e.Key);
}
}
Related
When a UI element ( control ) is focused in a uwp app it can be triggered with Spacebar or the Enter keys, this is not limited to Desktop but also helps in Xbox so user can navigate through the controls and press on any focused control to active its Command.
Use case
But in My use case I want only Enter key to trigger that behaviour and Spacebar should not do anything at all no matter which control is pressed on the screen.
The reason to this requirement is that I am building a MediaPlayer application and no matter which control or button is focused within the app when I press Spacebar I want to simply link it to the Play/Pause Behaviour of my media element.
Not a Duplicate
This question is not a duplicate of : UWP - Don't fire Click event when pressing space (like in Movies & TV app)
Because in the question linked above, the answer was only relevant if any of the AppBarButtons were focused so they will not do anything on pressing Space but only will be invoked with Enter. But in my use case I want to apply the same behavior even outside the MediaPlayerElement control. I have a NavigationView and MediaPlayerElement resides in one of the pages, so I want this behavior to work even when a NavigationViewItem is focused or any other control which can be focused and invoked should only be invoked with Enter and not Space.
Is there a app level solution where I can apply this behaviour at the very root control and it descends to all of its children i.e : whole app?
What I have tried
I have tried with the already answered question (linked above) and that works fine for its limited scenario. And I have also tried setting AllowFocusOnInteraction=false to every app bar button and also other extra controls I have in the style of my CustomMediaTransportControls. But this is also limited to MediaPlayerElement only and also it prevents tab navigation which is not good for accessibility.
You can do this by handling the PreviewKeyDown event higher in the visual tree hierarchy, for example in the Page.
Subscribe to the event in the Page constructor:
public MainPage()
{
this.InitializeComponent();
this.PreviewKeyDown += MainPage_PreviewKeyDown;
}
Or in XAML:
<Page ... PreviewKeyDown="MainPage_PreviewKeyDown">
And in the event handler set the KeyRoutedEventArgs to handled when the Space key was pressed:
private void MainPage_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == VirtualKey.Space)
{
e.Handled = true;
}
}
This way the key down event will never reach any control below in the hierarchy because the PreviewKeyDown event propagates the tree before the event takes place.
There are many ways could approach, You could listen the current Content PreviewKeyDown event to detect Space press.
public Scenario1()
{
this.InitializeComponent();
Window.Current.Content.PreviewKeyDown += Content_PreviewKeyDown;
}
private void Content_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
e.Handled = e.Key == VirtualKey.Space ? true : false;
}
You could also GLOBAL HOTKEY for your uwp app that could be used when your app's window not in foreground. For more derail you could check this blog .
When a ContextMenuStrip is opened, if the user types the first letter of a possible selection - it's as if he clicked on it. I want to intercept that and get the character that he clicked.
The following code does that, but with hard-coding the possible character. I want a generic way to do this, either by disabling the automatic selection by key stroke (leaving only the mouse clicks) or some way to intercept the character.
The following simplified code assumes I want to have a winform's Text to be the character typed, and the ContextMenuStrip has one option which is "A".
public Form1()
{
InitializeComponent();
contextMenuStrip1.KeyDown += contextMenuStrip1_KeyDown;
}
private void button1_Click(object sender, EventArgs e)
{
contextMenuStrip1.Show();
}
void contextMenuStrip1_KeyDown(object sender, KeyEventArgs e)
{
e.SuppressKeyPress = true;
if (e.KeyCode == Keys.A)
{
if (e.Shift) Text = "A";
else Text = "a";
}
}
Using the KeyPress event and checking e.KeyChar doesn't work because it doesn't get fired. (the "A" click-event gets fired instead.)
Using one of these: e.KeyCode, e.KeyData, or e.KeyValue doesn't work (without further hard-coding) because they accept a Shift as a Key.
As noted in the comment, you have to derive your own class from ContextMenuStrip so you can override the ProcessMnemonic() method.
Annotating this a bit, keyboard processing is very convoluted in Winforms. Shortcut keystrokes are processed very early, before they are dispatched to the control with the focus. Necessarily so, you would not want to implement the KeyDown event for every control so that you could make a shortcut keystroke work.
This works from the outside in and involves several protected methods, ProcessCmdKey, ProcessDialogChar and ProcessMnemonic. As well as OnKeyDown if the form's KeyPreview property is set, a VB6 compat feature. So the form gets a shot at it first, then it iterates controls from there, going from container to child controls.
The ToolStrip class (a base class for ContextMenuStrip) overrides the ProcessMnemonic() method to recognize key presses, mapping them to menu items. So in order to intercept this default processing, you have to override ProcessMnemonic() yourself to get a shot at the key press first.
I am writing a metro app where it makes sense for focus to jump to a single text box anytime the user starts typing. But I can't figure out how to implement this functionality locally, without modifying other user controls to detect keydown and forward focus to the text box.
In WinForms I would have used the form's "KeyPreview" property, which caused any key presses within the form's controls to fire form KeyDown/KeyPress/KeyUp events. I can't find any equivalent in metro.
I tried the naive solution of just forcing focus to the text box anytime it left, but that has obvious problems (e.g. buttons flicker instead of staying highlighted when you click and hold on them).
How can I ensure any keyboard typing goes to a specific text box?
The event needs to be placed on the current core window, which is the root element all controls are nested on.
Windows.UI.Xaml.Window.Current.CoreWindow.KeyDown += (sender, arg) => {
// invoked anytime a key is pressed down, independent of focus
}
Here you go ...
Responding to keyboard input (Metro style apps using C#/VB/C++ and XAML)
&&
Implementing keyboard accessibility (Metro style apps using C#/VB/C++ and XAML)
Pay special attention to routed events. There are examples there too.
Hope this helps.
In your xaml code u bind these to events to page::
Loaded="pageRoot_Loaded_1"
Unloaded="pageRoot_Unloaded_1"
and inside these methods u have to bind and unbind ur events for keydown or keypress
private void pageRoot_Loaded_1(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown += CoreWindow_KeyDown;
}
private void pageRoot_Unloaded_1(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown -= CoreWindow_KeyDown;
}
I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}
I got a form with a number of buttons on it (assume 20). In the middle, I got a User Control which is completely empty. The question is: how can I make it so that when the User Control is clicked, it will get keyboard focus?
Reason: I paint shapes in that User Control, with my mouse. The shapes are actually other User Controls. What I want to do is be able to use the keyboard to move those shapes. But I cannot seem to correctly be able to grab the Keyboard focus. The Key_Down events just don't reach my main (drawing into) User Control.
So, in other words, how can we have keyboard focus in a control has no focusable items on it? How can one make an keyboard-unfocusable control, catch those events? Any way of grabbing these events window-wide, other than going raw-WIN32 API hardcore?
A UserControl was very much designed to be a container control for other controls. It abhors getting the focus and tries to pass it off first chance it gets. You should not be using a UserControl here, given that you don't put any controls inside of it. A Panel control will suffice. Which has the exact same problem, it doesn't want to get focus either.
Surgery is required to override its behavior. Everything you need is in this answer.
Add this to your user control code to capture keyboard input:
/// <summary>Keys which can generate OnKeyDown event.</summary>
private static readonly Keys[] InputKeys = new []
{ Keys.Left, Keys.Up, Keys.Right, Keys.Down, };
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
if(Array.IndexOf<Keys>(InputKeys, e.KeyCode) != -1)
{
e.IsInputKey = true;
}
base.OnPreviewKeyDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
// just to illustrate this works
MessageBox.Show("KeyDown: " + e.KeyCode);
}
See http://msdn.microsoft.com/en-us/library/aa969768.aspx. You can assign keyboard focus by
1. Set the usercontrol.Focusable=true;
2. Use Keyboard.Focus(usercontrol).
You need to set the CommandRouting flag on your control to true.
The command routing dependency property is defined in a public API (MS.VS.Editor.dll) and your adornment will want to use that API to indicate that it is handling its commands instead of allowing the containing text view handle them. You can do this with from your control’s initialization.
Microsoft.VisualStudio.Editor.CommandRouting.SetInterceptsCommandRouting(this, true);