Mouse on control immediately lost - wpf

my intention is to capture the mouse events for a specific control, but the mouse capture is instantly lost
XAML
<Window x:Class="TryMouseCapture.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>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label x:Name="lbl" BorderBrush="Black" BorderThickness="2" GotMouseCapture="lbl_GotMouseCapture" IsEnabled="True" LostMouseCapture="lbl_LostMouseCapture" MouseLeftButtonDown="lbl_MouseLeftButtonDown">Mouse captured here</Label>
<Label Grid.Row="1" BorderBrush="Red" BorderThickness="2">Click here</Label>
<Button Grid.Row="2" Click="Button_Click">Capture Mouse in the first label</Button>
</Grid>
</Window>
code behind
private void lbl_GotMouseCapture(object sender, MouseEventArgs e)
{
Label label = (Label)sender;
var b = label.IsMouseCaptured;
}
private void lbl_LostMouseCapture(object sender, MouseEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var b = Mouse.Capture(lbl);
}
private void lbl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
}
So after clicking the button, the lbl_GotMouseCaptureis called, and then immediately lbl_LostMouseCapture follows.
Is there something else to do, besides calling Mouse.Capture(lbl); ?

For me the code works. But setting the b variable implies that you are setting breakpoints. I would replace those by Debug statements to start with..

You should set also
e.Handled = true;
in your Button_Click event handling to make it working everywhere.

Related

Same click event for both Button and Grid

I read about Routed events today and tried to provide same click event handler for both a normal button and a custom grid button. Stackpanel is handling the routed button click event, and to invoke same handler I am firing a click event from grid's mousedown event. Code is without error but not working as expected.
Button click brings the messagebox but clicking the grid with mouse does nothing.
<Window x:Class="RoutedEventPr.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="550" Width="525">
<StackPanel Background="Transparent" Button.Click="Button_Click_1">
<Grid Width="200" Height="100" Background="Aqua" MouseDown="Grid_MouseDown_1">
<Ellipse StrokeThickness="4" Width="200" Height="100" Fill="Beige"/>
<TextBlock Text="Press" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
<Button x:Name="SureBtn" Content="Pause !" Width="200" Margin="0 10 0 0"/>
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Height="200" Source="I://fancybtn.jpg"/>
<Label Content="Start the game"/>
</StackPanel>
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("Are you sure !");
}
Button.Click event is routed event with bubbling strategy set to Bubble.
That means it will bubble up to visual parent till root until it was handled. In your case, you raise an event from Window, so it will bubble up from Window to its parent which is null.
You have to raise the event from child control of StackPanel so that it can bubble up to StackPanel.
XAML
<Grid x:Name="grid" Width="200" Height="100" Background="Aqua"
MouseDown="Grid_MouseDown_1">
<Ellipse StrokeThickness="4" Width="200" Height="100" Fill="Beige"/>
<TextBlock Text="Press" HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
Code behind
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
grid.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));
}
I did below changes and it works now.
private void Grid_MouseDown_1(object sender, MouseButtonEventArgs e)
{
SureBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent, this));
}

Set focus to a usercontrol when it is made visible

I am showing a MessageBox and want the user to be able to copy the contents of the message using CTRL+C. The problem is that I can't seem to set focus to the dialog.
The MessageBox is implemented in MVVM. To show it I just make a usercontrol visible (centre screen) and disable the main view.
The copy command is implemented using a Prism DelegateCommand:
<UserControl.InputBindings>
<KeyBinding Key="C" Modifiers="Control" Command="{Binding CopyCommand}"/>
</UserControl.InputBindings>
If I tab onto on of the message box button the CopyCommand fires. However I cannot get it to work initially when the dialog is shown.
How do I get the usercontrol to accept focus or to attach the KeyBinding to the whole of the usercontrol?
Note: I need an MVVM solution as don't want any code in the code behind file.
In situations when using MVVM pattern and need to interact with the user interface, I always try to implement this solution through an attached behavior. Attached behavior is very powerful and convenient solution that fully satisfies the MVVM pattern, which can also be used in the Blend (with a pre-defined interface).
In this case, I created an attached behavior VisibleFocusBehavior, which set a IsVisibleChanged event handler, wherein the focus is set in the case of the visibility of the element.
To avoid the appearance of dotted box, when the control gets focus, I set FocusVisualStyle="{x:Null} for UserControl.
VisibleFocusBehavior
public class VisibleFocusBehavior
{
#region IsFocusEnabled Dependency Property
public static readonly DependencyProperty IsFocusEnabledProperty;
public static void SetIsFocusEnabled(DependencyObject DepObject, bool value)
{
DepObject.SetValue(IsFocusEnabledProperty, value);
}
public static bool GetIsFocusEnabled(DependencyObject DepObject)
{
return (bool)DepObject.GetValue(IsFocusEnabledProperty);
}
#endregion
#region BringToFrontBehavior Constructor
static VisibleFocusBehavior()
{
IsFocusEnabledProperty = DependencyProperty.RegisterAttached("IsFocusEnabled",
typeof(bool),
typeof(VisibleFocusBehavior),
new UIPropertyMetadata(false, IsFocusTurn));
}
#endregion
#region IsFocusTurn
private static void IsFocusTurn(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
UIElement element = sender as UIElement;
if (e.NewValue is bool && ((bool)e.NewValue) == true)
{
if (element != null)
{
element.IsVisibleChanged += new DependencyPropertyChangedEventHandler(ElementIsVisibleChanged);
}
}
}
#endregion
#region ElementIsVisibleChanged Handler
private static void ElementIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
UIElement visibilityElement = sender as UIElement;
if (visibilityElement.IsVisible == true)
{
visibilityElement.Focus();
}
}
#endregion
}
Example of using
<UserControl x:Class="UserControlFocusHelp.TestUserControl"
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"
xmlns:local="clr-namespace:UserControlFocusHelp"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300"
xmlns:AttachedBehaviors="clr-namespace:UserControlFocusHelp.AttachedBehaviors"
AttachedBehaviors:VisibleFocusBehavior.IsFocusEnabled="True"
FocusVisualStyle="{x:Null}">
<UserControl.InputBindings>
<KeyBinding Key="C"
Modifiers="Control"
Command="{Binding CopyCommand}" />
</UserControl.InputBindings>
Test window
XAML
<Grid>
<local:TestUserControl x:Name="TestUserControl"
Width="300"
Height="300"
Focusable="True"
Visibility="Collapsed" />
<Button Width="100"
Height="30"
Content="Visible"
HorizontalAlignment="Left"
Click="Button_Click" />
</Grid>
Code-behind
private void Button_Click(object sender, RoutedEventArgs e)
{
TestUserControl.Visibility = Visibility.Visible;
}
Full example is available at this link.
There is a simple way to set focus to a control. Here's an example:
<UserControl
FocusManager.FocusedElement="{Binding ElementName=txtNickname}">
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="txtNickname" Grid.Row="1" />
</Grid>
</Grid>

DataGrid - Mouse enter + leave row events

I would like to subscribe to the mouse enter and leave events of a DataGridRow.
My XAML for the DataGrid looks like this at the moment:
<toolkit:DataGrid ItemsSource="{Binding DisplayedSearchResults}"
caliburn:Message.Attach="[Event MouseDoubleClick] = [OpenDocument()]"
SelectedItem="{Binding SelectedRow, Mode=TwoWay}" Margin="7"
AutoGeneratingColumn="DataGrid_AutoGeneratingColumn"
IsReadOnly="True" Grid.Row="0"
Sorting="ResultsDataGrid_Sort">
<toolkit:DataGrid.Resources>
<Style TargetType="Button"></Style>
</toolkit:DataGrid.Resources>
</toolkit:DataGrid>
How can I do this using Caliburn if possible, but code-behind if not?
I ended hooking up in the code-behind:
MyView.xaml.cs:
public partial class MyView : UserControl
{
public SearchResultsView()
{
InitializeComponent();
SearchResultsGrid.LoadingRow += DataGrid_PreparingRow;
}
public void DataGrid_PreparingRow(object sender, DataGridRowEventArgs args)
{
args.Row.MouseEnter += Row_MouseEnter;
args.Row.MouseLeave += Row_MouseLeave;
}
public void Row_MouseEnter(object sender, MouseEventArgs args)
{
// do some stuff
}
public void Row_MouseLeave(object sender, MouseEventArgs args)
{
// do some stuff
}
}
MyView.xaml:
<UserControl x:Class="MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<toolkit:DataGrid Name="SearchResultsGrid" />
</Grid>
</UserControl>

Drag and Drop WPF ComboBox, Buttons, Radio Buttons, etc

I have a problem, i've already read tutorials, blogs, etc about drag and drop on WPF (i'm using VS10).
The problem is I need to have a toolbox with buttons,combobox, radio button,etc sothe user can drag it and drop it(copy) on a work space (canvas or whatever).
I managed to do drag and drop from textbox and images but that doesn't work for me, when i tried on buttons or combobox it just doesnt work, i assume it is cause of the click event by default, i don't know what the problem is tho. Here is what i've tried with a button.
<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>
<TextBox Height="22" HorizontalAlignment="Left" Margin="84,36,0,0" Name="textBox1" VerticalAlignment="Top" Width="103" Text="Drag" />
<TextBox Height="40" HorizontalAlignment="Left" Margin="225,136,0,0" Name="textBox3" VerticalAlignment="Top" Width="124" Text="Drop" />
<Label Content="DragLabel" Height="26" HorizontalAlignment="Left" Margin="284,36,0,0" Name="label1" VerticalAlignment="Top" Width="80" MouseDown="label1_MouseDown" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="84,122,0,0" Name="button1" VerticalAlignment="Top" Width="75" MouseDown="button1_MouseDown" AllowDrop="True" IsEnabled="True" Click="button1_Click" />
<Rectangle Height="100" HorizontalAlignment="Left" Margin="149,199,0,0" Name="rectangle1" Stroke="Black" VerticalAlignment="Top" Width="200" AllowDrop="True" Fill="#FFDCA1A1" />
</Grid>
My Code Behind ...
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void label1_MouseDown(object sender, MouseButtonEventArgs e)
{
Label lbl = (Label)sender;
DragDrop.DoDragDrop(lbl, lbl.Content, DragDropEffects.Copy);
}
private void button1_MouseDown(object sender, MouseButtonEventArgs e)
{
var dependencyObject = (Button)sender;
DragDrop.DoDragDrop(dependencyObject, dependencyObject, DragDropEffects.Move);
}
private void button1_Click(object sender, RoutedEventArgs e)
{
return;
}
}
Thank You in advance guys. Btw sry about my english :s...
Thx again!
Luis
Have you tried using the PreviewMouseDown event instead of MouseDown? Your code will get called before the Button can capture the click.
WPF elements normally use RoutedEvents which often have a corresponding "Preview" event that uses the Tunneling Routing Strategy, which will be sent to all parents before the element that actually raised the event. This allows you to perform your operation in response to the MouseDown before the Button gets a chance to try to execute a click action.
private void button1_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var dependencyObject = (Button)sender;
DragDrop.DoDragDrop(dependencyObject, dependencyObject, DragDropEffects.Move);
}
will work as mentioned by Abe

How to close popup in silverlight?

I have ListBox. when i click on ListBox item I have to show item information in popup But it does not close after clicking out side. I am creating popup in itemsselected event. how to handle popup close?
One approach is to create a canvas with a transparent background that you make visible at the same time as opening the Popup and attaching to is Mouse down event to closed the popup. Like this:-
Xaml:-
<Grid x:Name="LayoutRoot" Background="White" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Popup x:Name="MyPopup" Closed="MyPopup_Closed" HorizontalOffset="100" VerticalOffset="100" Opened="Popup_Opened">
<ListBox x:Name="PopupChild" MaxHeight="300" LostFocus="PopupChild_LostFocus">
<sys:String>Hello World</sys:String>
</ListBox>
</Popup>
<Button Content="Open Popup" Grid.Row="1" Click="Button_Click" />
<Canvas x:Name="PopupOpen" Visibility="Collapsed" Background="Transparent" Grid.RowSpan="2" MouseLeftButtonDown="PopupOpen_MouseLeftButtonDown" />
</Grid>
Code:-
private void Button_Click(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = true;
}
private void Popup_Opened(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Visible;
}
private void PopupChild_LostFocus(object sender, RoutedEventArgs e)
{
MyPopup.IsOpen = false;
}
private void PopupOpen_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyPopup.IsOpen = false;
}
private void MyPopup_Closed(object sender, EventArgs e)
{
PopupOpen.Visibility = Visibility.Collapsed;
}
Note that its important that if your popup contains a control that can receive the focus that you also handle LostFocus.
This is similar to a question that I had. Take a look at How to dismiss a popup in Silverlight when clicking outside of the control?. I posted in my solution an extension method that's been very helpful in making popups close when clicking outside of them.
I'm not quite sure what you mean by "clicking out side" because popups act in a modal way.
You should set up your popup window as a ChildWindow. Then you can handle the Closed event.
Here's a very simple sample that shows a selected string from a listbox in a main window.
First the main window:
<UserControl x:Class="PopupTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel Orientation="Vertical">
<ListBox x:Name="SomeList" Width="100" Height="100" />
<TextBlock x:Name="DialogResult" Width="100" />
</StackPanel>
</Grid>
In the codebehind, the popup is triggered when the list selection changes. Simply set up a Closed handler. In this example, I simply put the chosen list item into a textblock, then upon closing the popup, I just put the dialog result in a textblock on the main window (to show if the user pushed ok or cancel).
public MainPage()
{
InitializeComponent();
SomeList.SelectionChanged += new SelectionChangedEventHandler(SomeList_SelectionChanged);
SomeList.Items.Add("one");
SomeList.Items.Add("two");
SomeList.Items.Add("three");
}
void SomeList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var popup = new SomePopup();
popup.Closed += new EventHandler(popup_Closed);
popup.ChosenItem.Text = (string)SomeList.SelectedItem;
DialogResult.Text = "";
popup.Show();
}
void popup_Closed(object sender, EventArgs e)
{
var popup = sender as SomePopup;
if (popup.DialogResult == true)
DialogResult.Text = "Ok";
else
DialogResult.Text = "Cancel";
}
The popup closes when the user pushes Ok or Cancel, because the DialogResult value is set in the popup's code-behind:
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}

Resources