Silverlight MouseLeave not firing - c#

Considering that piece of code :
XAML:
<Grid x:Name="LayoutRoot">
<Border x:Name="brd1" Height="100" Width="100" Background="Blue"
MouseLeftButtonUp="brd1_MouseLeftButtonUp"
MouseLeave="brd1_MouseLeave" />
</Grid>
C# :
private void brd1_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
brd1.Visibility = System.Windows.Visibility.Collapsed;
}
private void brd1_MouseLeave(object sender, MouseEventArgs e)
{
MessageBox.Show("Mouse Leave");
}
Why is the MouseLeave not firing when setting Visibility = Collapsed (ie : when I click on the border)?
Is there a way to always catch the MouseLeave event even if the control disappears (or one of its parent)? I cannot listen to the MouseButtonUp event, since my control can appear/disappear asynchronously at any time.
(note : my application is far more complex than that, this was just a simple example of what I need to do)

Related

WPF Mouse Events Bug?

I found a workaround for this bug I want to understand why this is happening. Is it bug? Is there a better workaround? Am I doing something wrong?
Here is the plainest code that I could come up with to show the problem. Inside MainWindow.xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<local:AnnoyingBlock Margin="5"/>
<TextBlock Text="Tweedle Dee" MouseDown="MoveWindow"/>
</StackPanel>
</Grid>
Inside MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MoveWindow(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left) Dispatcher.Invoke(DragMove);
e.Handled = true;
}
}
class AnnoyingBlock : TextBlock
{
public AnnoyingBlock()
{
MouseLeftButtonUp += OnMouseUp;
Text = "Tweedle Dumb";
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Boom");
}
}
Run that code and click/drag the text Tweedle Dee. It works as expected and the window is moved with the mouse. Click on the text Tweedle Dumb. The message box shows up.
Now, from the AnnoyingBlock declaration in the xaml, remove the margin and run it again. Run it again and you should see that clicking anywhere in the Tweedle Dee text pops up the message box when you release the mouse. Remove the MouseDown event from the TextBlock in the xaml and run it again. The MouseUp event on the sibling control is no longer fired.
Why does an event on a sibling control get fired? Why does this only happen when you have an event on the control (even though it's a different event MouseDown vs MouseUp)? Why does adding a margin stop this from happening?

Flyout causing the app to crash [Windows 10] C# XAML

I want the program to show the attached Flyout when user Holding the control (on the mobile) or when the user Right-click the control (on PC).
Here is my XAML :
<DataTemplate x:DataType="data:Cards" x:Key="card">
<StackPanel x:Name="cardstack" Holding="cardstack_Holding" KeyDown="cardstack_KeyDown" >
<StackPanel Background="Blue" Height="100" />
<FlyoutBase.AttachedFlyout>
<MenuFlyout x:Name="optionpass">
<MenuFlyoutItem x:Name="delete" Text="Delete" Click="delete_Click"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
</StackPanel>
</DataTemplate>
and this is my C# :
private void cardstack_Holding(object sender, HoldingRoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
private void cardstack_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.RightButton)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
}
When I tap and Hold the Stackpanel on the mobile simulator, the Holding event works, but when I Right-click on my PC, it crashes! It says that "There are no attached Flyout!". I do not know what is wrong.
"Have you tried RightTapped event? Is it working?"
Yes and No :(
I just found out the solution to solve my problem.
Turns out you have to name the MenuFlyout like my one is x:Name = "option_menu", and the Flyoutbase.AttachedFlyout cannot be in the DataTemplate, means you have to put it anywhere else except in the DataTemplate, so that the .cs file can find the name of the MenuFlyout.
Here is my C# :
public void cardstack_Holding(object sender, HoldingRoutedEventArgs e)
{
option_menu.ShowAt(sender as FrameworkElement);
e.Handled = true;
}
private void cardstack_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Pointer pointr = e.Pointer;
if (pointr.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
Windows.UI.Input.PointerPoint pointrd = e.GetCurrentPoint(sender as UIElement);
if (pointrd.Properties.IsRightButtonPressed)
{
option_menu.ShowAt(sender as FrameworkElement);
}
}
e.Handled = true;
}
Notice that before this I use ShowAttachedFlyout, now I use option_menu.ShowAt.
KeyDown event somehow did not work with my app, so I used PointerPressed instead.
Hope this helps. (0w0)/

C# / WPF Unmask password inside the passwordBox

How could I unmasked and masked the password inside the passwordBox whenever I click the checkBox? I'm using C# WPF template.
Here is my .XAML code:
<PasswordBox x:Name="passwordBox_password" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="5" Height="25" />
<CheckBox x:Name="checkBox_showPassword" Grid.Row="3" Grid.Column="1" Margin="5,0,5,5" Content="show password" Checked="checkBox_showPassword_Checked" Unchecked="checkBox_showPassword_Unchecked" />
Here is my .CS code:
private void checkBox_showPassword_Checked(object sender, RoutedEventArgs e)
{
// what to do here ?
}
private void checkBox_showPassword_Unchecked(object sender, RoutedEventArgs e)
{
// what to do here ?
}
Or is there another way to do it in WPF?
It's very simple to do that.
First you should to add the value PasswordChar in your PasswordBox:
<PasswordBox Name="PasswordHidden" PasswordChar="•"/>
Next under the PasswordBox tag you should to add a TextBox with Visibility value setted to Hidden:
<TextBox Name="PasswordUnmask" Visibility="Hidden"/>
And a trigger to show / hide the password, for example a simple text or a button. In my case I'm using a simple text.
<TextBlock Name="ShowPassword"/>
Next you need to add 3 different events in the trigger element, for example (this is valid for TextBlock or Image, if you want to use a Button you should to choose another events):
<TextBlock x:Name="ShowPassword" Text="SHOW" PreviewMouseDown="ShowPassword_PreviewMouseDown" PreviewMouseUp="ShowPassword_PreviewMouseUp" MouseLeave="ShowPassword_MouseLeave"/>
The events are PreviewMouseDown PreviewMouseUp and MouseLeave but you can choose the appropriate event for your situation.
Now in your code you need to program the functions:
private void ShowPassword_PreviewMouseDown(object sender, MouseButtonEventArgs e) => ShowPasswordFunction();
private void ShowPassword_PreviewMouseUp(object sender, MouseButtonEventArgs e) => HidePasswordFunction();
private void ShowPassword_MouseLeave(object sender, MouseEventArgs e) => HidePasswordFunction();
private void ShowPasswordFunction()
{
ShowPassword.Text = "HIDE";
PasswordUnmask.Visibility = Visibility.Visible;
PasswordHidden.Visibility = Visibility.Hidden;
PasswordUnmask.Text = PasswordHidden.Password;
}
private void HidePasswordFunction()
{
ShowPassword.Text = "SHOW";
PasswordUnmask.Visibility = Visibility.Hidden;
PasswordHidden.Visibility = Visibility.Visible;
}
The following link will bring you to the answer you are looking for my good sir. Mr Lamas did a great job of answering the how-to so I'd rather redirect you to the answer :)
showing password characters on some event for passwordbox
I recommend Using MahApps.Metro ... after installing it from nuget.org ... you must use it in the head of your xaml like this
xmlns:controls="http://metro.mahapps.com/winf/xaml/controls"
and then ... just use it's style for your PasswordBox control
<PasswordBox Style="{StaticResource MetroButtonRevealedPasswordBox}" />
you can even change the content for the show icon using the controls:PasswordBoxHelper.RevealButtonContent attached property

Why does the MouseMove event not work if mouse loses focus on object?

I basically have a simple problem in my program that I just want to make sure goes right. It should on the click of the mouse button add the MouseEventHandler and then move the circle along with the mouse until the event handler gets removed. I simplified the code to the very basics:
XAML:
<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 Name="grid1" Background="White" MouseLeftButtonUp="grid_MouseUp">
<Ellipse Height="50" HorizontalAlignment="Left" Margin="12,12,0,0" Name="ellipse1" Stroke="{x:Null}" VerticalAlignment="Top" Width="50" Fill="Black" MouseLeftButtonDown="ellipse1_MouseDown" />
</Grid>
</Window>
C#:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private static Point _oldPoint = new Point(), _newPoint = new Point();
private void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)
{
_oldPoint = e.GetPosition(grid1);
grid1.MouseMove += new MouseEventHandler(grid_MouseMove);
}
private void grid_MouseUp(object sender, MouseButtonEventArgs e)
{
grid1.MouseMove -= new MouseEventHandler(grid_MouseMove);
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
_newPoint = e.GetPosition(grid1);
ellipse1.Margin = new Thickness(ellipse1.Margin.Left - _oldPoint.X + _newPoint.X, ellipse1.Margin.Top - _oldPoint.Y + _newPoint.Y, 0, 0);
_oldPoint = _newPoint;
}
}
Now in general this code works fine and I think is quite neat as it doesn't check the movement of the mouse until one actually presses the button. However, my question is as follows:
I had to add the MouseMove event to the grid rather than to the circle, because once the mouse pointer loses focus of the circle (by moving the mouse too fast) it doesn't trigger the MouseMove event anymore. But why exactly does that happen? At the beginning of the event the mouse was definitely above the circle and then it moved. Yes, it moved away from the circle but shouldn't that still trigger the event?
You can capture the mouse and handle all events in your ellipse.
<Grid Name="grid1" Background="White">
<Ellipse Height="50" HorizontalAlignment="Left" Margin="12,12,0,0" Name="ellipse1" Stroke="{x:Null}" VerticalAlignment="Top" Width="50" Fill="Black"
MouseLeftButtonDown="ellipse1_MouseDown" MouseLeftButtonUp="ellipse1_MouseUp" />
</Grid>
with this code behind
private void ellipse1_MouseDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(ellipse1);
_oldPoint = e.GetPosition(grid1);
ellipse1.MouseMove += new MouseEventHandler(ellipse1_MouseMove);
}
private void ellipse1_MouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
ellipse1.MouseMove -= new MouseEventHandler(ellipse1_MouseMove);
}
I've moved and renamed grid_MouseMove to ellipse1_MouseMove.
Adding to what Peter said, if you use the Grid.MouseDown event and checked if the oldPoint is within Ellipse and have then handled the MouseMove event, this odd behavior wont be seen.
I also suggest exploring drag events.
A control only gets the mouse-events as long as the mouse is hovering over that particularly control.
If moving to a new control, the mouse is getting unhooked from the old control and hooked to the new control.
There are ways where you can create a global hook attached to the entire process, but I guess this is not what we are talking about.

Dragging a window in WPF using DragMove method and click handler on the same button

I need a button for two purposes:
- Users can drag the application's window using the button
- Users can simply click the button to toggle visibility of some other element in the window.
The button is a PNG image.
I am trying to do it in the following way:
XAML:
<Button Name="toggleButton" Click="toggleButton_Click" Canvas.Left="177" Canvas.Top="0">
<Button.Template>
<ControlTemplate>
<Image Source="/FootballRssReader;component/images/ball.png" MouseLeftButtonDown="toggleButton_MouseLeftButtonDown"/>
</ControlTemplate>
</Button.Template>
</Button>
C#:
private void toggleButton_Click(object sender, RoutedEventArgs e)
{
contentVisible = !contentVisible;
content.Visibility = contentVisible ? Visibility.Visible : Visibility.Collapsed;
}
private void toggleButton_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
The problem is that only the window moving works. Clicks on the button don't invoke the Click event handler. When I remove MouseLeftButtonDown event handling from the button's image, the Click event is executed.
Can anybody help me? Is it possible to create such a button?
I tried setting Handled to false in the Image but it didn't help.
Thanks, Michal
DragMove starts a modal message loop and doesn't return until the mouse button is released, so by the time the button receives the MouseLeftButtonDown event it's already lost the chance to click.
I'm assuming you don't want the Click to happen if the user drags the window. One approach is to do something similar to drag-drop, and only call DragMove if the mouse starts moving while it is pressed. Attach handlers to PreviewMouseLeftButtonDown and PreviewMouseMove on the Button:
<Button Name="toggleButton" Click="toggleButton_Click"
Canvas.Left="177" Canvas.Top="0"
PreviewMouseMove="toggleButton_PreviewMouseMove"
PreviewMouseLeftButtonDown="toggleButton_PreviewMouseLeftButtonDown">
<Button.Template>
<ControlTemplate>
<Image Source="/FootballRssReader;component/images/ball.png"/>
</ControlTemplate>
</Button.Template>
</Button>
Record the mouse position in the PreviewLeftMouseButtonDown handler, and then start the DragMove in the PreviewMouseMove handler if the mouse has started moving:
private Point startPoint;
private void toggleButton_PreviewMouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(toggleButton);
}
private void toggleButton_PreviewMouseMove(object sender, MouseEventArgs e)
{
var currentPoint = e.GetPosition(toggleButton);
if (e.LeftButton == MouseButtonState.Pressed &&
toggleButton.IsMouseCaptured &&
(Math.Abs(currentPoint.X - startPoint.X) >
SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(currentPoint.Y - startPoint.Y) >
SystemParameters.MinimumVerticalDragDistance))
{
// Prevent Click from firing
toggleButton.ReleaseMouseCapture();
DragMove();
}
}

Categories

Resources