Does anybody know whether one can trigger prism command with a shortcut? What I mean is I want to be able to define binding of a command to keyboard shortcut in declarative manner, like ClientUI does:
Are there any opensource libraries for that purpose? Or maybe code samples?
I found this question but I don't think that it answers mine.
I've created such gesture trigger. And I'd like to share it with you guys. Basically, it is System.Windows.Interactivity trigger which can parse gestures represented as strings. Usage is as simple as in ClientUI:
<UserControl>
<i:Interaction.Triggers>
<behaviors:KeystrokeCommandTrigger Command="{Binding SaveChangesCommand}" Gesture="Ctrl+Shift+S" />
<behaviors:KeystrokeCommandTrigger Command="{Binding RejectChangesCommand}" Gesture="Ctrl+Shift+R" />
<behaviors:KeystrokeCommandTrigger Command="{Binding NewItemCommand}" Gesture="Ins" />
<behaviors:KeystrokeCommandTrigger Command="{Binding DeleteSelectedItemCommand}" Gesture="Del" />
<behaviors:KeystrokeCommandTrigger Command="{Binding UploadSomethingCommand}" Gesture="Ctrl+Shift+U" />
</i:Interaction.Triggers>
</UserControl>
The code is on pastie.
You could write an attached behavior that has a listens to the KeyUp event and then calls the Command. The complication comes in translating something like Gesture="Ctrl+Shift+A". You would need to write a parser to figure out exactly what key combination that string represents.
Related
I am trying to use an attached event to invoke an ICommand.
I am using the Microsoft.Toolkit.Mvvm NuGet package, along with the Microsoft.Xaml.Behaviors.Wpf Nuget package.
I have had success starting a Storyboard using the <BeginStoryBoardAction /> within the <FOO.Triggers /> by defining an <EventTrigger /> and setting the RoutedEvent equal to the name of the attached event in question.
However, to my knowledge, there exists no way to invoke an ICommand using anything provided within the <EventTrigger />. By which I mean, there is nothing that I can use within the body of the <EventTriggers.Actions /> block (similar to <Behaviors.InvokeCommandAction />) which will result in the ICommand being invoked.
In compliance with the Minimal, Complete and Verifiable example, to demonstrate what I am trying to achieve, you can reference the project on GitHub - https://github.com/AbbottWC/MCVE_AttachedEventFailure.
Or
Open Visual Studio. Create a WPF Application (Targeting .Net Core 3.1)
Tools -> NuGet Package Manager -> Manage Packages for this solution
Add the Microsoft.Toolkit.Mvvm (for the RelayCommand class) and the Microsoft.Xaml.Behaviors.Wpf packages.
In the App.Xaml.cs
private RelayCommand testCommand = new RelayCommand(( ) => MessageBox.Show("Event Captured!", "Success!"));
public RelayCommand TestCommand => testCommand;
In the MainWindow.xaml
Define the namespace xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
Rename local to l
Add the following to the body of the XAML before the closing </Window> tag:
<i:Interaction.Triggers>
<!--This will work, and is present only to prove the problem lies not with the Command or how it is being accessed.-->
<i:EventTrigger EventName="MouseEnter">
<i:EventTrigger.Actions>
<i:InvokeCommandAction Command="{Binding TestCommand, Source={x:Static l:App.Current}}" />
</i:EventTrigger.Actions>
</i:EventTrigger>
<!--This will not work, and is meant to provide an example of the problem.-->
<i:EventTrigger EventName="Mouse.MouseEnter">
<i:EventTrigger.Actions>
<i:InvokeCommandAction Command="{Binding TestCommand, Source={x:Static l:App.Current}}" />
</i:EventTrigger.Actions>
</i:EventTrigger>
</i:Interaction.Triggers>
So to restate my question, is what I am trying to achieve here possible? Is it just not possible to use an attached event in this way?
Thanks.
From what I understand, the EventTrigger can only listen to events that the source object "owns". So to answer your question, this is not possible using the EventTrigger class.
If you look at the source, when you pass Mouse.MouseEnter, it tries to get that event from the target type. Also, since you did not specify the target, it defaults to the AssociatedObject, which is Window in your case.
Type targetType = obj.GetType();
EventInfo eventInfo = targetType.GetEvent(eventName);
Now the problem I find, is if it cannot find the event, it only throws an exception when the source object is not null, and in your case you haven't specified one, so it silently fails. Not sure why the designers made it this way.
Now, I did find this blog post, which describes exactly how you can workaround this problem:
https://sergecalderara.wordpress.com/2012/08/23/how-to-attached-an-mvvm-eventtocommand-to-an-attached-event/
Basically, you inherit from EventTriggerBase<T> and in the OnAttached method you need to call AddHandler on your AssociatedObject to add the event.
Dеаr Colleagues,
I'm having issues with the following code:
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="BeforeTextChanging">
<core:InvokeCommandAction Command="{Binding ConfirmEmailCommand, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
I want to emphasize, that the command triggers MOST of the times. The code works. The problem is, it sometimes doesn't. Command isn't called by the evens that otherwise will call it.
The behavior belongs to a Textbox inside a TemplatedControl, which exists inside a ContentDialog. I have similar code in other controls that are part of a ContentDialog and they all have such intermittent problems.
Does anyone have experience with such problems and can you elaborate on a possible fix? What order of control construction and property allocation could cause the Command to not be available for invocation during the event?
I have a WPF project (C#, MVVM Light, Visual Studio 2010).
I have a bit of a problem regarding separation of concerns (MVVM) which basically is this: I have a command in a view model. I have a context menu that I want to call that command. So far so good. The problem is that the command needs to coordinates that the mouse was clicked.
To be a little more specific, the ContextMenu only appears if you click on a particular Canvas control, and it's the coordinates within said Canvas control that I want.
The easy way to do this is to manage it all in the code behind of the XAML document (and I have been able to do it that way), but I'd rather have it within my ViewModel if I can do so. The reason is that there are calls to my data model within this command so we end up with a problem of separation.
I am aware of PassEventArgsToCommand, and I'm aware that it's a bad practise, however in this case I'm not sure I can see a way around it. So for the moment I did try that, and it looks like this:
<ContextMenu x:Key="BackgroundMenu">
<MenuItem Header="Add new node here">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.DataContext.AddNewNodeAtLocationCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</MenuItem>
</ContextMenu>
So now my command, within the view model, looks like this:
void AddNewNodeAtLocationExecute(RoutedEventArgs e)
{
return;
}
Within that method I'd like to get those mouse coordinates, but I don't know if it's possible. e.OriginalSource is 'MenuItem', which doesn't help much.
So how can I do this? Can I do this? Or should I just have this one command handled by the code behind? Said code will involve a call to the database, which is why I'm being so particular about the separation.
Thanks in advance.
Well I stumbled across this question which speaks about separation of concerns and what not.
In the end I did a merging of the two ideas I had. Firstly, the ContextMenu simply links to the code behind. At that point I get the coordinates I want. Then that code behind gets the DataContext of the view (where the command I want is) and calls the Execute method (having first checked the 'can' method).
I suppose it's as ideal as you're going to get.
I'm little confused about RelayCommand and EventToCommand in Mvvmlight.
It seems that EventToCommand handle the EventTrigger and call a RelayCommand to do job.
Such as:
<i:Interaction.Triggers>
<i:EventTrigger x:Uid="i:EventTrigger_1" EventName="MouseLeftButtonUp">
<cmd:EventToCommand x:Uid="cmd:EventToCommand_1" Command="{Binding Form_MouseLeftButtonUpCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Is my understanding correct?
So, can we use RelayCommand directly with EventTrigger, no need to use EventToCommand?
Thanks for your help!
EventToCommand is a custom behavior. It is first provided by Expression blend team and now Part of WPF 4. If you're not using WPF4. you require Blend SDK from here.
Behaviors encapsulates functionality as reusable components. These are to be used when feature is not present by default. For example Adding Command support to Label, Combobox etc.
can we use RelayCommand directly with EventTrigger, no need to use EventToCommand?
No. RelayCommand is a shortcut to avoid code redudnency to define custom commands.It extends ICommand whose delegates can be attached for Execute(T) and CanExecute(T). It is similar to DelegateCommand of Prism library.
<cmd:EventToCommand x:Uid="cmd:EventToCommand_1" Command="{Binding Form_MouseLeftButtonUpCommand}" PassEventArgsToCommand="True"/>
In above line cmd:EventToCommand is additional feature to the underlying control. Form_MouseLeftButtonUpCommand is the Command it executes. This command can be encapsulated as RelayCommand.
Thank Tilak for your useful answer.
With the explanation from Tilak, I did mess up like putting a binding in a event handler (such as Button GotFocus="{Binding DoJob}") --> Build failed and found that Event Handler like this does not support Binding. We can only bind in Command (such as Button Command="{Binding DoJob}" /> and default event is invoked in this situation, with button, it should be Click event).
Do something stupid will help me to understand the life more - LOL
can we use RelayCommand directly with EventTrigger, no need to use
EventToCommand?
Actually, I intend NOT to use EventToCommand, and I found the solution for that: use InvokeCommandAction instead (belongs to System.Windows.Interactivity - Mvvm-light also refers to this assembly).
Does exist a similar EventToCommand (behavior's) on Android?
Example Silverlight/WPF:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<Commanding:EventToCommand Command="{Binding DataContext.EditEventTypeCommand,
RelativeSource={RelativeSource AncestorType=telerik:RadGridView}}"
CommandParameter="{Binding}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
If you are using mvvmcross, then bindings exist for all events which have EventHandler signatures - so you can just use bindings like:
'Click':{'Path':'MyViewModelCommand'}
There are plenty of examples of this in the samples, plus there are several questions oh here - search for MvvmCross and click.
If you need to bind to an event which has an EventHandler<T> signature then you can add this yourself - see mvvmcross touch command binding in android
I'm not sure I have understood your question (I don't know Silverlight) but you can do as follows:
In your XML:
<Button ...
android:onClick="onMyButtonClicked".../>
In your java file
public void onMyButtonClicked(View sender) { ... }
There are no other ways to specify event handlers in Android XML, I think. You can specify a lot of properties though.