KeyDown event not raising from a grid - c#

Here I have sample window with a grid. I need to capture event when key is pressed. But it is not raising when I click grid area and then press key. It will work only if Textbox is focused. I know it will work if I capture it from Window. But I have other application with few usercontrols and I need to capture it from distinct ones. I tried to set Focusable.false for Window and true for Grid but it not helps.
Any solutions?
<Window x:Class="Beta.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Closed="Window_Closed_1" Focusable="False">
<Grid KeyDown="Grid_KeyDown_1" Focusable="True">
<TextBox x:Name="tbCount" HorizontalAlignment="Left" Height="35" Margin="310,49,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="83"/>
</Grid>

Right this is weird. This is clearly a focus problem, still I can not understand why the grid do not take Focus, even when we click on it.
Though there is a workaround: create an handler for the loaded event of the grid:
<Grid x:Name="theGrid" KeyDown="Grid_KeyDown_1" Focusable="True" Loaded="TheGrid_OnLoaded">
And then force focus in your code behind:
private void TheGrid_OnLoaded(object sender, RoutedEventArgs e)
{
theGrid.Focus();
}
Your keydown event will work after that.
Hope it helps.

I had the same issue with a Universal Windows Platform (UWP) app. I attached the event to a grid in XAML but it would only work when the focus was on the TextBox. I found the answer (not just a workaround) on MSDN: https://social.msdn.microsoft.com/Forums/en-US/56272bc6-6085-426a-8939-f48d71ab12ca/page-keydown-event-not-firing?forum=winappswithcsharp
In summary, according to that post, the event won't fire because when focus to the TextBox is lost, it's passed higher up so the Grid won't get it. Window.Current.CoreWindow.KeyDown should be used instead. I've added my event handlers to the page loaded event like this:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.KeyDown += coreWindow_KeyDown;
Window.Current.CoreWindow.KeyUp += CoreWindow_KeyUp;
}
This works as expected for me.

I tried using the Focus Method too, to no avail, until I set the Focusable property to true ( It was default to False. )

I had the same problem, I've used PreviewKeyDownevent and it worked for me.

Related

Global event handler for TextBox getting focus by mouse click

I have a situation when I want to detect when a TextBox, anywhere in the application, has been brought into focus by the user clicking on it with the mouse, or touch. I have "solved" this by adding a global event handler like this:
Application.Current.MainWindow.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(txt_MouseLeftButtonUp), true);
...
void txt_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is TextBox)
{
// Do somthing
}
}
However, if the user clicks the edges of a textbox instead of in the middle, quite often an hosting control (Grid, Border etc.) receives the mouse event and somehow passes this on to the contained TextBox, that will handle it and receive focus. This makes the approach above fruitless as the TextBox will not be the e.OriginalSource in this case and I have found no way of identifying that a TextBox was brought into focus by click.
Deriving TextBox and overriding OnMouseDown for instance, will catch this event and I guess this path could be explored to find a solution to the problem but that would require me to use a custom TextBox everywhere.
Anyone out there with a nice solution for this?
This is an example that will trigger the problem. By clicking the edges of the TextBoxes, the grid will handle the mouse event and focus will be passed on to the TextBox.
<Grid>
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Red">
<TextBox>2323</TextBox>
</Grid>
<Grid Margin="200,0,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="Red" Focusable="False">
<TextBox>2323</TextBox>
</Grid>
</Grid>
The GotMouseCapture event seems to work:
AddHandler(UIElement.GotMouseCaptureEvent,
new MouseEventHandler(OnGotMouseCapture), true);
...
void OnGotMouseCapture(object sender, MouseEventArgs e)
{
if (e.OriginalSource is TextBox)
{
// ...
}
}
When I click on TextBox elements with the mouse this event handler is fired, however focus changes made via keyboard do not fire the event.
Simply handle the GotFocus event for each TextBox.

MouseDown event of image in usercontrol not fireing

I made a usercontrol in WPF with an image in it. I declared a MouseDown event for this image:
<Image x:Name="imgState" Height="300" Width="300" MouseDown="imgState_MouseDown" OpacityMask="#00000000" />
I placed this usercontrol on my application form, but the event isn't fireing. I'm pretty new to WPF and I read about RoutedEvents but I don't really understand it. I would be happy if someone could help and explain this to me!
Update
Changing to PreviewMouseDown didn't fire the event too. I tried setting the background to transparent and even tried with a blank 300x300 image. The grid workaround doesn't fire the event too. Here is how my code behind looks like:
private void imgState_MouseDown(object sender, MouseButtonEventArgs e)
{
//Some code here
}
Update 2
Here is my whole XAML file:
<UserControl x:Class="TicTacToe.controls.SingleField"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Image x:Name="imgState" MouseDown="imgState_MouseDown" Height="300" Width="300" Stretch="None" OpacityMask="#00000000"/>
</Grid>
</UserControl>
I removed the source again because I set one from code behind at runtime and adding a transparent/clear image didn't helped.
You probably want PreviewMouseUp instead of MouseDown event
<Image x:Name="imgState" Height="300" Width="300"
PreviewMouseUp="ImgState_OnPreviewMouseUp"
PreviewMouseDown="ImgState_OnPreviewMouseDown"/>
Either of the two, you can capture the event from there.
If the answer above does not help:
Not a very nice solution but does work so many times:
Wrap your image with a grid on which you will have your event...
<Grid MouseDown="imgState_MouseDown">
<Image/>
</Grid>
Okay I solved the problem myself.
The problem was the setting OpacityMask="#00000000" that prevented the image from appearing so there were, as #lll said, nothing to hit. I don't know when the setting was set, but I think it happened automatically while expanding the Representation tab.
Thanks for helping me!

Cannot drag text into a WPF window

I'm trying to set up a WPF window so that it can accept different types of data via Drag and Drop. If I make a new project and set the window to the following:
<Window x:Class="DropShare.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" AllowDrop="True" DragEnter="Window_DragEnter">
<Grid>
</Grid>
</Window>
And set the code-behind to:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_DragEnter(object sender, DragEventArgs e)
{
}
}
I only ever get DragEnter firing for files. It never fires for anything else - text, images, etc.
Is there something I'm missing? All the tutorials I've read have seemed to suggest this is all that's needed as the DragEnter event handler let's me state what I accept.
So your code works fine for me. But try this...
In your Window:
<Label Background="Purple" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Drag from here!" MouseDown="Label_MouseDown"/>
and in your code behind:
private void Label_MouseDown(object sender, MouseButtonEventArgs e)
{
DragDrop.DoDragDrop(this, "This is just a test", DragDropEffects.All);
}
Then drag from the label into the window and see if your event fires.
If this works, it may have something to do with the permissions level between Visual Studio and your outside environment (possibly).
See:
https://superuser.com/questions/59051/drag-and-drop-file-into-application-under-run-as-administrator
In WPF drag and drop feature always has to deal with DragDrop Class, Please check here how to do drag and drop across applications

How to handle TextBlock.KeyDown event, when TextBlock is a part of UserControl?

I have this simple UserControl:
<UserControl x:Class="WPFTreeViewEditing.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="Hello, world!" KeyDown="TextBlock_KeyDown" />
</Grid>
</UserControl>
I want to handle TextBlock.KeyDown event. So, I've added an event handler to the code-behind:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void TextBlock_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show("Key up!");
}
}
but it doesn't fire. What's wrong?
UPDATE.
PreviewKeyDown doesn't fire too.
This UserControl is used in HierarchicalDataTemplate then:
<Window x:Class="WPFTreeViewEditing.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFTreeViewEditing"
Title="MainWindow" Height="265" Width="419">
<Grid>
<TreeView ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:ViewModel}" ItemsSource="{Binding Items}">
<local:UserControl1 />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
From the documentation for UIElement.KeyDown:
Occurs when a key is pressed while focus is on this element.
You're using TextBlock which doesn't have the focus, so your KeyDown event will be handled by another control.
You can switch to TextBox and appy some styles so it'll look and behave like TextBlock, but you'll be able to get the focus and handle the event.
You should use PreviewKeyDown event instead of KeyDown event.
Ok, even though this question was posted a long time ago I had the same problem and found a way to get KeyDown events working, though it might not be what you're looking for I'll post the code to help future people with the same problem.
First thing first a KeyDown event handler in an Xaml Object will only fire off if that object has focus. Therefore you need a CoreWindow event handler, it's kind off the same thing but it will always run no matter what object or thing has focus. The following will be the code.
//CLASS.xaml.h
ref class CLASS{
private:
Platform::Agile<Windows::UI::Core::CoreWindow> window;
public:
void KeyPressed(Windows::UI::Core::CoreWindow^ Window, Windows::UI::Core::KeyEventArgs^ Args);
//CLASS.xaml.cpp
CLASS::CLASS(){
InitializeComponent();
window = Window::Current->CoreWindow;
window->KeyDown += ref new TypedEventHandler
<Windows::UI::Core::CoreWindow^, Windows::UI::Core::KeyEventArgs^>(this, &CLASS::KeyPressed);
};
void CLASS::KeyPressed(Windows::UI::Core::CoreWindow^ Window, Windows::UI::Core::KeyEventArgs^ Args){
SimpleTextBox->Text = Args->VirtualKey.ToString();
};
Basically you want a value to hold your window and use that to create a new TypedEventHandler. For safety you'll generally want to do this in your class' constructor a function that's only called once the moment the class starts (I still prefer the constructor though).
You can use this method to create an event handler for any event. Just change the "KeyDown" for another attribute like KeyUp, PointerMoved, PointerPressed and change the "&CLASS::KeyPressed" to the name of the function you want to be fired the moment you get an event of a corresponding type.

Why doesn't keyboard input work for a ScrollViewer when the child control has input focus?

Why doesn't keyboard input work for a ScrollViewer when the child control has input focus?
This is the scenario. A WPF window opens. It sets the focus to a control that is embedded in a ScrollViewer.
I hit the up and down and left and right keys. The ScrollViewer doesn't seem to handle the key events, anyone know why?
This is the simplest possible example:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
FocusManager.FocusedElement="{Binding ElementName=control}"
>
<Grid>
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
>
<ItemsControl
x:Name="control"
Width="1000"
Height="1000"
/>
</ScrollViewer>
</Grid>
</Window>
When you start the app that contains this window, "control" appears to have the focus as I intended. Pressing the key seems to result in bubbling key events reaching the ScrollViewer (I checked for this using WPF Snoop). I can't work out why it doesn't respond to the input.
The problem
A ScrollViewer ignores all KeyDown events whose OriginalSource is not the ScrollViewer. The OriginalSource on a KeyDown is set to the focused control, therefore the ScrollViewer ignores it when a child has the focus.
The solution
Catch the KeyDown event and raise a copy of it directly on the ScrollViewer so it will have the correct OriginalSource, like this:
void ScrollViewer_KeyDown(object sender, KeyEventArgs e)
{
if(e.Handled) return;
var temporaryEventArgs =
new KeyEventArgs(e.KeyboardDevice, e.InputSource, e.Timestamp, e.Key)
{
RoutedEvent = e.RoutedEvent
};
// This line avoids it from resulting in a stackoverflowexception
if (sender is ScrollViewer) return;
((ScrollViewer)sender).RaiseEvent(temporaryEventArgs);
e.Handled = temporaryEventArgs.Handled;
}
the event handler can be added in XAML:
<ScrollViewer KeyDown="ScrollViewer_KeyDown" />
or in code:
scrollViewer.AddHandler(Keyboard.KeyDownEvent, ScrollViewer_KeyDown);
The latter is more applicable if the ScrollViewer is inside a template somewhere and you have code to find it.
In order for the ScrollViewer to react to your keyboard keys - it needs to have IsFocused="True" - right now it's child has the focus.
To prove it - try in your Loaded event to manually set focus to the ScrollViewer (you might have to set IsFocusable="True" for it to work on the ScrollViewer) - now the keys should work. If you want it to work otherwise, you need to set the appropriate EventHandlers on the ScrollViewer (KeyDown/KeyPress etc.)
Similar issue with no keyboard navigation when using ScrollViewer inside an ItemsControl.Template. Adding Focusable and IsTabStop resolved the issue in my case.
<ScrollViewer
Focusable="True"
IsTabStop="True">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>

Categories