How to detect DoubleClick in WPF ToggleButton - c#

In my WPF application I have Toggle Button, I want to detect when user double click on it (in both cases if it checked or unchecked).
How can I do that?
Thanks in advance

You can use the OnPreviewMouseDoubleClick event
xaml:
<ToggleButton Height="75" Width="100" PreviewMouseDoubleClick="Control_OnPreviewMouseDoubleClick"/>
code-behind:
private void Control_OnPreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var toggleButtton = sender as ToggleButton;
if (toggleButtton != null)
{
if (toggleButtton.IsChecked.HasValue)
{
if (toggleButtton.IsChecked.Value)
{
// Checked
}
else
{
// Unchecked
// this will re-check the button if double-click unchecks it
//
toggleButtton.IsChecked = true;
toggleButtton.Focus();
}
}
}
}

Use PreviewMouseDoubleClick event (msdn):
XAML:
<ToggleButton x:Name="tButton" Height="30" Content="MyButton"
PreviewMouseDoubleClick="tButton_PreviewMouseDoubleClick"
/>
Code-behind:
private void tButton_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
tButton.IsChecked = !tButton.IsChecked.Value;
e.Handled = true;
//...
}

This event is pretty easy with togglebuttons
Xaml you write the following to get an EventHandler:
<ToggleButton Name="button1" MouseDoubleClick="button1_DoubleClick" />
In c# you write the following to get an EventHandler:
button1.MouseDoubleClick += new MouseButtonEventHandler(button1_DoubleClick);
And in both cases you need:
void button1_DoubleClick(object sender, MouseButtonEventArgs e)
{
}

Related

Keyboard accelerator firing when writing to Textbox

Click event of Button is fired when pressing D while writing to Textbox.
Is there an elegant way how to suppress Keyboard Accelerator while Textbox is focused?
XAML:
<StackPanel Orientation="Vertical">
<TextBox></TextBox>
<Button Click="Button_Click" Content="Button with "D" as keyboard accelerator" Margin="0,10">
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="D"></KeyboardAccelerator>
</Button.KeyboardAccelerators>
</Button>
<TextBlock x:Name="ButtonClickCounter"></TextBlock>
</StackPanel>
C#:
int buttonClickCounter;
private void Button_Click(object sender, RoutedEventArgs e)
{
ButtonClickCounter.Text = $"Button clicked {++buttonClickCounter} times";
}
EDIT:
Why Accelerator with Modifier (Alt+D or Ctrl+D) is not solution?
I am creating video player and I found that one-key shortcuts are neat solution for fast operations with video player (same as in VLC).
Best Solution so far:
Creating custom KeyboardAccelerator, that checks if focus is set to text box. Only edit in code that need to be done is changing KeyboardAccelerator to AcceleratorWithHandledActionIfTextboxIsFocused.
public class AcceleratorWithHandleDActionIfTextboxIsFocused:KeyboardAccelerator
{
public AcceleratorWithHandleActionIfTextboxIsFocused()
{
Invoked += AcceleratorWithHandleActionIfTextboxIsFocused_Invoked;
}
private void AcceleratorWithHandleActionIfTextboxIsFocused_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
var focusedElement = FocusManager.GetFocusedElement();
if (focusedElement.GetType() == typeof(TextBox))
args.Handled = true;
}
}
part of XAML:
<Button.KeyboardAccelerators>
<custom:AcceleratorWithHandleDActionIfTextboxIsFocused Key="D"></KeyboardAccelerator>
</Button.KeyboardAccelerators>
I agree with #Thomas Weller in his comments as for not using a single letter as a keyboard accelerator...
But everybody has their own requirements, anyway, you could try to e.handle = true your event when textbox is focused.
Something like this:
public void Button_Click(object sender, ExecutedRoutedEventArgs e)
{
if (textBox.isFocused)
{
e.handled = true;
}
}

How to unselect other AppBarToggleButton UWP

I m doing an UWP project, and I'm using the CommandBar.
In my command Bar I have multiple AppBarToggleButton, when I click to one of them I wan't that the other AppBarToggleButton are unselect.
Is there an options to do that ?
Here is a symple code :
<CommandBar>
<AppBarToggleButton Icon="Shuffle" Label="Shuffle" Click="AppBarButton_Click" />
<AppBarToggleButton Icon="RepeatAll" Label="Repeat" Click="AppBarButton_Click"/>
<CommandBar.Content>
<TextBlock Text="Now playing..." Margin="12,14"/>
</CommandBar.Content>
You just need to x:Name your buttons and manually set IsChecked to False whenever the other one is clicked.
private void AppBarButton1_Click(object sender, RoutedEventArgs e)
{
AppBarButton2.IsChecked = false;
}
Update
A pure XAML solution would be using bindings. Note you will need an InvertedBooleanConverter here.
IsChecked="{x:Bind Toggle1.IsChecked, Converter={StaticResource InvertedBooleanConverter}, Mode=TwoWay}"
Bonus
I really dislike the binding approach so here's a pure XAML solution built with a behavior. Note you will need to first install the XAML Behaviors from the Nuget Package Manager -
Install-Package Microsoft.Xaml.Behaviors.Uwp.Managed -Version 2.0.0
This AutoDeselectToggleButtonBehavior behavior below basically gets all the AppBarToggleButtons once the CommandBar is loaded, subscribe to all their Click events and in the handlers, simply de-select all the other toggles except the clicked one.
public class AutoDeselectToggleButtonBehavior : Behavior<CommandBar>
{
private IEnumerable<AppBarToggleButton> _toggleButtons;
protected override void OnAttached()
{
AssociatedObject.Loaded += OnLoaded;
base.OnAttached();
}
protected override void OnDetaching()
{
foreach (var toggle in _toggleButtons)
{
toggle.Click -= OnToggleClick;
}
AssociatedObject.Loaded -= OnLoaded;
base.OnDetaching();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Children extension method:
// https://github.com/JustinXinLiu/Continuity/blob/master/Continuity/Extensions/UtilExtensions.cs#L25
_toggleButtons = AssociatedObject.Children().OfType<AppBarToggleButton>();
foreach (var toggle in _toggleButtons)
{
toggle.Click += OnToggleClick;
}
}
private void OnToggleClick(object sender, RoutedEventArgs e)
{
var clickedToggle = (AppBarToggleButton)sender;
foreach (var toggle in _toggleButtons)
{
if (toggle != clickedToggle)
{
toggle.IsChecked = false;
}
}
}
}
Once it's in place, just attach it to your CommandBar like the following -
<CommandBar>
<Interactivity:Interaction.Behaviors>
<local:AutoDeselectToggleButtonBehavior />
</Interactivity:Interaction.Behaviors>
Clean and reusable. :)

Shortcut hotkey for WPF

I used UserControl for my application and i need to put shortcut key for my application i placed this code but not working.Anyone suggestion plz
My XAML Code
<Button Name="ucBtnUpload" ToolTip="Upload F2" Cursor="Hand" Click="ucBtnUpload_Click" KeyUp="ucBtnUpload_KeyUp_1" >
My Code Behind
private void ucBtnUpload_KeyUp_1(object sender, KeyEventArgs e)
{
if (e.Key == Key.F2)
{
Test opj = new Test();
opj.ShowDialog();
}
}
You need to try something similar to this
private void AddHotKeys()
{
try
{
RoutedCommand firstSettings = new RoutedCommand();
firstSettings.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Alt));
CommandBindings.Add(new CommandBinding(firstSettings , My_first_event_handler));
RoutedCommand secondSettings = new RoutedCommand();
secondSettings.InputGestures.Add(new KeyGesture(Key.B, ModifierKeys.Alt));
CommandBindings.Add(new CommandBinding(secondSettings , My_second_event_handler));
}
catch (Exception err)
{
//handle exception error
}
}
Events
private void My_first_event_handler(object sender, ExecutedRoutedEventArgs e)
{
//handler code goes here.
MessageBox.Show("Alt+A key pressed");
}
private void My_second_event_handler(object sender, RoutedEventArgs e)
{
//handler code goes here.
MessageBox.Show("Alt+B key pressed");
}
If you are following MVVM you could try this reference
<UserControl.InputBindings>
<KeyBinding Modifiers="Control"
Key="E"
Command="{input:CommandBinding EditCommand}"/>
See the reference
msdn adding key bindings
You should be able to do this in your xaml
<Window.InputBindings>
<KeyBinding Command="{Binding MyCommand}" Key="F2"/>
</Window.InputBindings>
<Button Command="{Binding MyCommand}"/>
MyCommand is an ICommand implemented in your windows' / view's viewmodel.
So both the button and the F2 inputbinding will execute the same command.

Open and Close the same window on the same button click

On my MenuItem at the moment I open up a Window. Then if the person chooses to click on that MenuItem again, I need the Window that was open to close.
Then obviously, if they click it the third time it will open and so fourth.
XAML
<MenuItem x:Name="btnHelp" Click="btnHelp_Click" Foreground="#FF7E8385" FontFamily="Calibri" FontSize="18" Margin="110,10,0,0" Height="30" Width="70" Style="{x:Null}" BorderBrush="Transparent" Background="Transparent" Cursor="Hand"/>
Code behind
private void btnHelp_Click(object sender, RoutedEventArgs e)
{
xamlHelp help = new xamlHelp();
help.Show();
}
You'll need to have the variable be an instance field, rather than a local variable, so it can be accessed between calls. At that point just close it if it exists, and recreate/show it if it doesn't:
private xamlHelp help = null;
private void btnHelp_Click(object sender, RoutedEventArgs e)
{
if (help != null)
{
help.Close();
help = null;
}
else
{
help = new xamlHelp();
help.Show();
}
}
You can keep track of whether the help is currently showing and show/hide based on that,
private xamlHelp help = new xamlHelp();
private bool showingHelp = false;
private void btnHelp_Click(object sender, RoutedEventArgs e)
{
if (showingHelp)
{
help.Hide();
}
else
{
help.Show();
}
}

How to prevent raise of LostFocus on MouseDown on an control

The question is pretty simple: How do I prevent LostFocus from getting raised on MouseDown on a control that already got focus?
I have the following control (temporary test with all the event bindings):
<Grid Name="gBase" Focusable="True" MouseUp="SetFocus" MouseDown="SetFocus" MouseMove="gBase_MouseMove" PreviewDragEnter="gBase_PreviewDragEnter" LostFocus="gBase_LostFocus" GotFocus="gBase_GotFocus" Background="DarkRed" Width="500" Height="250" />
And the following code behind:
private void SetFocus(object sender, MouseButtonEventArgs e)
{
Grid g = sender as Grid;
g.Focus();
}
private void gBase_LostFocus(object sender, RoutedEventArgs e)
{
Grid g = sender as Grid;
g.Background = Brushes.DarkRed;
}
private void gBase_GotFocus(object sender, RoutedEventArgs e)
{
Grid g = sender as Grid;
g.Background = Brushes.Aquamarine;
}
private void gBase_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Grid g = sender as Grid;
g.Focus();
}
}
private void gBase_PreviewDragEnter(object sender, DragEventArgs e)
{
Grid g = sender as Grid;
g.Focus();
}
The behaviour is almost of that I want to achieve, if I click on the Grid it get focus.
The problem is that if the Grid already got focus it will lose it while I have the mouse button down and not regain it until I release or move. My prefered behaviour would be to prevent that it loses focus in the first place.
The problem was that the parent ScrollViewer stole focus.
This was solved by using the event MouseLeftButtonDown and setting the MouseButtonEventArgs.Handled to true to prevent further handling of the event.
Working code:
<Grid Name="gBase" Focusable="True" MouseLeftButtonDown="SetFocus" LostFocus="gBase_LostFocus" GotFocus="gBase_GotFocus" Background="DarkRed" MinWidth="500" MinHeight="250" Width="500" Height="250" HorizontalAlignment="Left" />
private void SetFocus(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
Grid g = sender as Grid;
g.Focus();
}
Use some property or variable to store which control has actually focus. And after MouseDown compare if control already had focus and if so, then don't do code in LostFocus event.
Important is to update storing property, when focus is changed on other control.

Categories