I'm having issues with dynamically handling the MouseUp event. Test code with issue:
WPF:
<Window x:Class="WpfApplication1.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">
<Grid>
<Button x:Name="Button1" Content="Button1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
<Button x:Name="Button2" Content="Button2" HorizontalAlignment="Left" Margin="10,37,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
</Window>
C# behind:
using System.Windows;
using System.Windows.Input;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Button2.MouseLeftButtonUp += something;
}
private void something(object sender, MouseEventArgs e)
{
MessageBox.Show("TEST");
Button2.MouseLeftButtonUp -= something;
}
}
}
Now, I want the MessageBox with the text "TEST" to show only the first time after I click Button2, after I've clicked Button1. It doesn't show up. The same code works with the Click event instead, but I need MouseUp to get the mouse position. I've confirmed that the first function fires, but the second doesn't no matter what I try. Help?
See the Remarks section in ButtonBase.Click:
The ButtonBase marks the MouseLeftButtonDown event as handled in the
OnMouseLeftButtonDown method and raises the Click event. Hence, the
OnMouseLeftButtonDown event will never occur for a control that
inherits from ButtonBase. Instead, attach an event handler to the
PreviewMouseLeftButtonDown event, or call AddHandler(RoutedEvent,
Delegate, Boolean) with handledEventsToo set to true.
Since MouseLeftButtonDown is handled internally, you will also get no
MouseLeftButtonUp event. You could however use the PreviewMouseLeftButtonUp event instead.
Related
I have noticed in my WPF application a strange behavior. If I edit or remove a text in any text box and try to click afterwards on a canvas, the first MouseLeftButtonDown event is often swallowed. If I try a second time, it works.
For demonstrating the problem, I have created a minimalist demo.
XAML:
<Window x:Class="WPF_Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Click Demo" Height="300" Width="400">
<Grid>
<TextBox x:Name="textBox" Margin="10,10,10,0" TextWrapping="Wrap" VerticalAlignment="Top"/>
<Canvas Margin="10,38,10,10" MouseLeftButtonDown="Click" Background="Black"/>
</Grid>
</Window>
C#:
using System.Windows;
using System.Windows.Input;
namespace WPF_Demo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Click(object sender, MouseButtonEventArgs e)
{
System.Diagnostics.Trace.WriteLine("Click!");
}
}
}
Edit:
Seems to be a problem of my Windows. I can reproduce it even with Explorer.
Could You please help me, why GotFocus and LostFocusa event doesn't fired when I Click to image and then to textbox?
My XAML:
<Window x:Class="imageclick.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">
<Grid>
<StackPanel>
<Image Source="Untitled.png" GotFocus="GF" LostFocus="LF" Focusable="True"></Image>
<TextBox ></TextBox>
</StackPanel>
</Grid>
</Window>
I could not understand why GotFocus/LostFocus event never fired
Thanks in advance
Update: When I set the tabindex, when the tab reached the image event fired, but I could not reach with mouse click
Image isn't a Control. Only Controls can get focus.Instead of GotFocus and LostFocus use MouseEnter and MouseLeave events,
<StackPanel>
<Image Stretch="Uniform" Source="Untitled.png" Height="410" MouseEnter="Image_MouseEnter" MouseLeave="Image_MouseLeave"></Image>
<TextBox Height="65"></TextBox>
</StackPanel>
According to MSDN, UIElement.GotFocus event occurs when this element gets logical focus.
And logical focus differs from keyboard focus, it is raised when the value of the IsFocused property of an element in the route is changed from false to true.
So, in order to achieve it through mouse clicks, need to handle the respective mouse button events or simply handle MouseDown and set the focus to the sender.
private void Image_MouseDown(object sender, MouseButtonEventArgs e)
{
if (sender is Image)
{
(sender as Image).Focus();
}
}
This will set the IsFocused property of the Image to true.
Here is my XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="844.025" Width="678" MouseUp="somethingClicked">
<Grid MouseUp="somethingClicked">
<StackPanel MouseUp="somethingClicked" Margin="0,0,10,0">
<Button x:Name="btnClickMe" Content="Click Me!" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="101,22,0,0" MouseUp="somethingClicked"/>
<CheckBox x:Name="chkhandle" Content="CheckBox" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="241,28,0,0" RenderTransformOrigin="-0.588,1.188"/>
<ListBox x:Name="lstEvents" HorizontalAlignment="Left" Height="604" VerticalAlignment="Top" Width="416" Margin="29,66,0,0"/>
</StackPanel>
</Grid>
And here is the C# Code:
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
protected int eventCounter = 0;
public MainWindow()
{
InitializeComponent();
}
private void somethingClicked(object sender, RoutedEventArgs e)
{
eventCounter++;
String message = "#" + eventCounter.ToString() + ":\r\n" +
" Sender: " + sender.ToString() + ":\r\n" +
" Source: " + e.Source + ":\r\n" +
" Original Source: " + e.OriginalSource;
lstEvents.Items.Add(message);
e.Handled = (bool) chkhandle.IsChecked;
if (e.Handled)
lstEvents.Items.Add("Completed");
}
}
}
I have the following issues with this example:
1)The MouseUp event is not fired on clicking the button.
2)The event doesn't bubble up. Clicking somewhere on the form displays:
Sender:WpfApplication4.MainWindow:
Source:WpfApplication4.MainWindow:
Original Source: System.Windows.Controls.Border.
If I understand rightly, when button is clicked, first it should be executed at Window level (which it does now), then Grid, then stack and finally text label. Is the code wrong or is my understanding of the concept faulty?
The MouseUp event is not fired on clicking the button.
Because the first fires is an event at the Button.Click, and when it works, it conflicts with the event MouseUp. Quote from here:
ButtonBase inherits from UIElement, a Button will also have access to all of the mouse button events defined for UIElement. Because the Button does something in response to button presses, it swallows the bubbling events (e.g. MouseLeftButtonDown and MouseDown). You can still detect these lower level button press events by adding handlers for the tunneling events (e.g. PreviewMouseLeftButtonDown and PreviewMouseDown).
Try to replace the Button on Label, and you'll get the desired result:
Try handling the PreviewMouseDown event instead. You can still
attach that from XAML. In your handler
Attach the event handler in code instead. Use the signature of
AddHandler
.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Grid1.MouseUp += new MouseButtonEventHandler(Grid1_MouseUp);
}
private void Grid1_MouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Mouseup");
}
Microsoft wrote a very nice explanation Routed Events Overview
exactly the same thing will happen with MouseUpand PreviewMouseUp events
in your case the e.Handled = (bool) chkhandle.IsChecked; stops the routing of the event.
if you want to debug the events you can use Snoop it will illustrate very nicely which events happened on which objects and who handled them.
There is an override available to handle events, even though they were marked as handled. It requires that you add your handler through code as the following:
MainWindow.AddHander(UIElement.MouseUpEvent, new MouseButtonEventHandler(button1_MouseUp), true);
That last parameter specifies whether you want to accept events that were handled already or not. If you add that handler to your main window, you'll notice that the routed MouseUp events from your button are indeed bubbling up, (but their e.Handled indicates that they were already handled).
I have Page, and it loses focus when I tap on an empty part of it. I tried putting a Border as the background, but that loses focus too when I tap it. Why does this happen?
What I really need to do is disable a WebView when the user opens the AppBar or the Settings Charm
Some example code to demonstrate the problem (watch the output window):
XAML:
<Page
x:Name="Pagey"
x:Class="FocusTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:FocusTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" GotFocus="Focus" LostFocus="LoseFocus">
<Grid x:Name="RootGrid" Background="{StaticResource ApplicationPageBackgroundThemeBrush}" GotFocus="Focus" LostFocus="LoseFocus">
<StackPanel>
<Button x:Name="Clicky" Content="Clicky" GotFocus="Focus" LostFocus="LoseFocus" HorizontalAlignment="Center"></Button>
<Border x:Name="Border" Width="100" Height="100" Background="Red" GotFocus="Focus" LostFocus="LoseFocus"></Border>
<Button x:Name="Clicky2" Content="Clicky2" GotFocus="Focus" LostFocus="LoseFocus" HorizontalAlignment="Center"></Button>
</StackPanel>
</Grid>
</Page>
Code behind:
using System.Diagnostics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace FocusTest
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
void Focus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Focus({0})", (sender as FrameworkElement).Name);
}
void LoseFocus(object sender, RoutedEventArgs e)
{
Debug.WriteLine("LoseFocus({0})", (sender as FrameworkElement).Name);
}
}
}
Look like your Border is inside the RootGrid So that every time when you tap Border's tap event will occur and LostFocus Event fired. Better you can set LostFocus event on the same RootGrid. Then it may work fine. Please try it.
Thanks.
I'm creating a UserControl consisting of a TextBox and a ListView. I want keyboard focus to remain with the TextBox as long as the control has keyboard focus (selection changes in the ListView shouldn't remove keyboard focus from the TextBox).
I've tried catching GotKeyboardFocus in the ListView and passing keyboard focus back to the TextBox using Keyboard.Focus(), but this seems to cancel any selection operation in the ListView. The below code shows the problem. Does anyone know how to achieve this functionality?
<Window x:Class="WpfApplication5.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">
<StackPanel>
<TextBox x:Name="TextBox1" />
<ListView x:Name="ListBox1" Keyboard.GotKeyboardFocus="ListBox1_GotKeyboardFocus">
<ListViewItem Content="Able" />
<ListViewItem Content="Baker" />
<ListViewItem Content="Charlie" />
</ListView>
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Input;
namespace WpfApplication5
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void ListBox1_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Keyboard.Focus(TextBox1);
}
}
}
Instead, have you considered just capturing keystrokes and putting those keystrokes into your TextBox?
<Window PreviewKeyDown="Window_PreviewKeyDown" >
<Grid>
<TextBox x:Name="TextBox1" />
<ListBox />
</Grid>
</Window>
Then in your window's code-behind:
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
TextBox1.Text += e.Key.ToString();
}
You'll have to do extra work for anything like special characters (backspace, etc), and obviously a Key handler for your "Enter" or "Post" operation, but it gives you the ability to just free-form type while the Window has focus and to properly handle the keystrokes as necessary.
It looks like it's possible to change focus in the MouseUp event. I think if you do it too early, like in the GotKeyboardFocus event, you'll steal focus before the listview can handle the event and select the chosen item.
<StackPanel>
<TextBox x:Name="TextBox1" />
<ListView x:Name="ListBox1" MouseUp="ListBox1_MouseUp">
<ListViewItem Content="Able" />
<ListViewItem Content="Baker" />
<ListViewItem Content="Charlie" />
</ListView>
</StackPanel>
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
TextBox1.Focus();
}
If you are calling your WPF window from a WinForm you must use this:
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(wpfWindow);
wpfWindow.show();
from the MSDN documentation.
Thats how I solved my keyboard problem.
IceX
This is a hack, but what if instead of listening to the GotKeyboardFocus event, you listen to the SelectionChanged event on the ListBox?
Put Focusable=false on your ListView.
Ok, this was driving me crazy. Even though set focus to UserControl every time lost focus, still couldn't get my command hot keys to work. All I had to do was to set the property Focusable to true, and voilĂ , it's working!