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 theMicrosoft.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
tol
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.
CodePudding user response:
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.