I am trying to implement ctrl+shift+mouseover on a button in wpf, mvvm.
I am doing something like:
<Button.InputBindings>
<KeyBinding Gesture="Ctrl+Shift" Command="{Binding KeyCommand}"
CommandParameter="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}"
/>
</Button.InputBindings>
or something like:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<i:InvokeCommandAction Command="{Binding MouseOverCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
I am unable to get the required behavior as Mouse Gesture does not support "MouseEnter" event.
I was trying to implement in a way like:
Step 1.- Through keybinding setting a variable in the viewmodel.
Step 2.- Accessing that variable's value on MouseEnter and do whatever in the command.
Any help is appreciated.
You could implement an attached behaviour that hooks up event handlers to the MouseEnter and MouseLeftButtonDown events and check whether the Ctrl and Shift keys are pressed by the time the events are raised, e.g.:
private void OnMouseEnter(object sender, MouseEventArgs e)
{
if ((Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
&& (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
{
TheCommand.Execute(null);
}
}
Related
I'm trying to handle the window closing using a solution similar to this, but the handler in my ViewModel is firing on application start, and not when closing.
XAML:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<command:EventToCommand Command="{Binding WindowClosing}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
ViewModel:
public RelayCommand<System.ComponentModel.CancelEventArgs> WindowClosing
{
get
{
return new RelayCommand<System.ComponentModel.CancelEventArgs>((args) => {});
}
}
The binding is obviously functioning, but it's just firing at exactly the wrong time. I thought the EventName="Closing" is what was supposed to bind to the actual closing event, but it doesn't matter what's contained there. It always fires on loading. What exactly is supposed to link this to the actual window closing event?
I have a mousewheel interactivity trigger on a StackPanel:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseWheel">
<cmd:EventToCommand Command="{Binding DataContext.PreviousWeekCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"
PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
and it works great with the PreviousWeekCommand as follows (snippet):
_previousWeekCommand = new RelayCommand<object>(param => ShiftDays(-7), param => (true));
The PassEventArgsToCommand is there because I'm trying to switch this to a different command that will detect if the user has scrolled up or down. The problem is, after a lot of searching, I still can't figure out how to structure the command to deal with the args. Here's what I have, but it doesn't work:
_scrollWheelCommand = new RelayCommand<MouseEventArgs>(ScrollWheel, can => true);
and then this is the ScrollWheel declaration:
public void ScrollWheel(MouseEventArgs args)
Problem is, I never get to this method when I breakpoint it. I also don't know if I'm routing the arguments in the correct way.
EDIT: Oh, and I get no errors.
Try using MouseWheelEventArgs instead of MouseEventArgs when declaring your RelayCommand. The Parameter type should match the event in order for that to work.
I'm developing a feature where a user can press 1 trough 9 or 'a' through 'z' that executes a command in a list. I built support for the numbers, but I don't really like the way I made it.
<Grid.InputBindings>
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D0" CommandParameter="0" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D1" CommandParameter="1" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D2" CommandParameter="2" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D3" CommandParameter="3" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D4" CommandParameter="4" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D5" CommandParameter="5" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D6" CommandParameter="6" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D7" CommandParameter="7" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D8" CommandParameter="8" />
<KeyBinding Command="{Binding ShortcutCharacterCommand}" Key="D9" CommandParameter="9" />
</Grid.InputBindings>
If I implement the remaining characters in the same manner, I'll have a huge list of bindings. Not only to support the letters, but also the numpad. I'd rather test for ranges of characters like I did with a Winform control in another part of our application with the code:
if (e.KeyValue >= '1' && e.KeyValue <= '9' ||
e.KeyValue >= 'A' && e.KeyValue <= 'Z')
{
FavoriteShortcutKeyPressedCallBack.Raise(e.KeyValue);
}
I really think it is possible but I can't seem to work out a solution or find one on the internet that adheres to the MVVM pattern.
So basically my question is, how can this be done in WPF/MVVM in a more generic, elegant manner?
How I solved it
I took the suggestion from the answer of mm8 to use EventToCommandBinding. This resulted in the following code in the XAML:
<i:Interaction.Behaviors>
<behaviors:EventToCommandBehavior Event="PreviewTextInput"
Command="{Binding TextInputCommand}"
PassArguments="True" />
</i:Interaction.Behaviors>
The ViewModel has a TextInputCommand that reads the text from the EventArgs and selects the corresponding item.
public RelayCommand<TextCompositionEventArgs> TextInputCommand { get; set; }
private void HandleTextInputCommand(TextCompositionEventArgs args)
{
SelectItemBoundToShortcut(args.Text);
}
At first I used the KeyDown event as user1672994 suggested in the comments. But found out that I had to account for different keyboard layouts and check separately for the numpad characters. Using the PreviewTextInput event just sends the typed text, which is exactly what I need.
You could handle the PreviewKeyDown event. Either in the code-behind of the view, from where you then invoke the command of the view model:
private void Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
var viewModel = DataContext as YourViewModel;
if (viewModel != null)
{
switch (e.Key)
{
case Key.D0:
viewModel.ShortcutCharacterCommand.Execute("0");
break;
case Key.D1:
viewModel.ShortcutCharacterCommand.Execute("1");
break;
//...
}
}
}
Or by using an interaction trigger as explained here:
MVVM Passing EventArgs As Command Parameter
You may also wrap the functionality defined in the event handler in an attached behaviour.
I have a tabbed GUI with each tab containing a Frame. I use the EventToCommand with the SelectionChangedEvent whenever a new TabItem is selected. I do this to update the state of the app. This all works fine - a little bit too fine, the event gets fired too often. Here is my problem:
How can I prevent the event from bubbling up the visual tree by setting the Handled property on the event when using the mvvm light eventToCommand feature?
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<mvvm:EventToCommand
Command="{Binding YourCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
Your command needs to provide parameter from method like RelayCommand . This parameter is event args providing Handled property. More here.
I need to trigger an event when the left mouse button gets released. I've tried this:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseClick" >
<i:InvokeCommandAction Command="{Binding OnBarGroupChangeCommand}" CommandParameter="{Binding ElementName=ReportsBarGroup, Path=Key}" />
</i:EventTrigger>
</i:Interaction.Triggers>
and this
<igWPF:OutlookBarGroup.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding OnBarGroupChangeCommand}" CommandParameter="{Binding ElementName=ReportsBarGroup, Path=Key}"/>
</igWPF:OutlookBarGroup.InputBindings>
These both work. The problem with both cases is that the event fires when the button gets pressed. I need it to fire only when the button gets released. The MouseBinding does not seem to support this. Is there a way to do this with Interaction? What is the best way to handle this? Thanks.
Try EventTrigger event name "MouseLeftButtonUp".
I'm not too familiar with C# but, as far as I'm aware, MouseBinding doesn't allow the support of mouse-up actions, only mouse-down. Take a look at the answer over here
Why don't your try this:
private void btn_MouseUp(object sender, MouseEventArgs e)
{
/////WHAT YOU WANT THE BUTTON TO DO/////
}
If you need to know more about mouse events enter HERE