Can't use long syntax for ActionMessage in Caliburn.Micro - c#

I'm trying to create an action for an attached event which I don't think CM supports out of the box.
This question/answer shows how to do this
using attached events with caliburn micro Message.Attach
but it requires using the long CM ActionMessage syntax, however, when I try to do this I get an 'ActionMessage does not exist in the XML namespace ' where blah is the CM namespace.
All of the examples also show this syntax; at the moment I've just put the code into the view which casts the DataContext to the ViewModel type and calls the appropriate method (I don't like this approach though as it couples the view to the VM and it's inconsistent with the rest of the app)
Anyone have any ideas why I can't see the ActionMessage?
e.g.
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<!-- this line throws the error -->
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs" />
</cal:ActionMessage>
</Helpers:RoutedEventTrigger>
</i:Interaction.Triggers>
I'm using SL5 and CM's SL5 assembly but no joy...
Interestingly, if I try to use 'ActionMessage' elsewhere it seems to be resolved correctly but of course it's not very useful outside of where I want it!
Update:
This is the view namespace def
xmlns:cal="http://www.caliburnproject.org"
I've tried the actual assembly qualified namespace and other combinations, all with the same issue

I've never had to use the ActionMessage syntax before, but as long as the control has an event that you're trying to attach to have you tried the following syntax:
<Button Content="Remove" cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />
I've been able to use that on a wide variety of controls without any issues.
http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/17/caliburn-micro-soup-to-nuts-pt-3-all-about-actions.aspx

I had similar issues I had to add an extra xaml tag before calling ActionMessage my corresponding sample to get it to work was:
<i:Interaction.Triggers>
<Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
<cal:Action.Target>
<cal:ActionMessage MethodName="SelectedDataChanged">
<cal:Parameter Value="$eventargs"/>
</cal:ActionMessage>
</cal:Action.Target>
</Helpers:RoutedEventTrigger RoutedEvent="Helpers:DataChanging.Changing">
</i:Interaction.Triggers>

Related

Is it possible to use invoke a command using an Microsoft.Xaml.Behaviors.EventTrigger with attached events?

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.

Intermittent error while using EventTriggerBehavior/InvokeCommandAction

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?

Can I omit the EventTrigger.Actions?

I am using WPF with the MVVM Pattern and Prism, and I'm using InteractionRequests for showing dialogs.
When I define the InteractionTriggers and their actions, I define them like this:
<i:Interaction.Triggers>
[Other event triggers]
<i:EventTrigger EventName="Raised" SourceObject="{Binding SomeConfirmationInteractionRequest}">
<i:EventTrigger.Actions>
<windowActions:DialogWindowAction />
</i:EventTrigger.Actions>
</i:EventTrigger>
</i:Interaction.Triggers>
Now I was checking my EventTriggers, and realized, I am missing one of the <i:EventTrigger.Actions> tags inside of the <i:EventTrigger>:
<i:EventTrigger EventName="Raised" SourceObject="{Binding SomeConfirmationInteractionRequest}">
<windowActions:DialogWindowAction />
</i:EventTrigger>
I was more confused that this part of my code worked, and there was no problem with it.
My question:
Why can it simply be omitted?
Can I just leave it out? Or does leaving the EventTrigger.Actions tag out change something that I haven't realized/experienced yet?
Yes, it can be safely omitted.
If you look at the TriggerBase class (up the inheritance tree of EventTrigger), you'll see it has an attribute [ContentProperty("Actions")]. This tells WPF to treat the Actions property as the direct child of the element in XAML.
This is widely used in WPF, e.g. ContentControls have the Content property (so you can write <Button><Image/></Button> instead of <Button><Button.Content><Image/></Button.Content></Button>), Panels have the Children property as their content, etc.

WP8 MvvmLight namespace missing and EventToCommand doesn't exist

I am using MVVM Light libraries only (from Nuget package) in my Windows Phone 8 project and I want to use EventToCommand in ToggleSwitch. I have these lines of codes:
<toolkit:ToggleSwitch x:Name="LockSwitch"
IsChecked="{Binding IsLock, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Toggled">
<Command:EventToCommand
Command="{Binding DataContext.NavigateToArticleCommand, ElementName=LayoutRoot}"
CommandParameter="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</toolkit:ToggleSwitch>
The problem is that VS shows errors:
Error 1 The name "EventToCommand" does not exist in the namespace
"clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8".
Error 2 The type 'Command:EventToCommand' was not found. Verify that
you are not missing an assembly reference and that all referenced
assemblies have been built.
Error 3 The tag 'EventToCommand' does not exist in XML namespace
'clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8'.
I have lines above in file Styles.xaml which is a ResourceDictionary and ToggleSwitch is part of a DataTemplate. I am including MvvmLight library using this line:
xmlns:Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"
What's wrong? Why I get that error? I was trying to use google but I couldn't find a solution.
The reference that you use to include the command is wrong. The correct reference is
xmlns:Command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
There's a trick to obtain this reference without writing a single line of code.
After you have downloaded the MvvmLight nuget package, compile your project and then open your xaml file in Expression Blend.
Then click the Assets icon on the left toolbar (the bottom one) and start typing "eventtocommand" (see picture below).
Once you see EventToCommand appear in the Assets panel, drag and drop it on top of your ToggleSwitch. That's it! The reference will be added into your xaml automatically as well as the actual command code.
Why not use Microsoft.Behaviors SDK ? (references, add reference, extensions, behavior sdk) Not sure but I think EventTrigger and mvvm light EventToCommand is deprecated now (because of behaviors sdk).
Code sample with Behaviors.SDK:
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
<toolkit:ToggleSwitch x:Name="LockSwitch"
IsChecked="{Binding IsLock, Mode=TwoWay}">
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Toggled">
<core:InvokeCommandAction Command="{Binding command}" CommandParameter="{Binding param}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</toolkit:ToggleSwitch>

Can use Blend SDK classes in code but not XAML (Prism Desktop)

I'm trying to use a CallMethodAction bound to a control in a WPF Window, using the method from the Prism library samples and documentation. For some reason, the XAML compiler refuses to acknowldge that the Microsoft.Expression.Interactivity.Core namespace even exists. However, I have no problem using the same classes from the same namespace in the code-behind for that view.
In XAML I've tried both the canonical namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ic="http://schemas.microsoft.com/expression/2010/interactions"
as well as the CLR namespace:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
The namespace Intellisense pop-up browser displays the first namespace but neither the XML nor CLR namespaces for the second. In either case, the following XAML fails to compile:
<Button HorizontalAlignment="Right" Content="Cancel">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ic:CallMethodAction />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
It has no problem finding the Interaction.Triggers tag, but complains that the CallMethodAction tag doesn't exist in the specified namespace. In fact, Intellisense on the ic namespace tag acts as if there is no such namespace. However, I do not get the error that the CLR namespace could not be found, which I do if I try to use a non-existant namespace.
However, in the constructor for this window, I can do this:
var x = new Microsoft.Expression.Interactivity.Core.CallMethodAction();
That compiles and runs fine. How is that even possible?
Try removing and re-adding reference to Microsoft.Expression.Interactions.dll and *.Interactivity.dll
It happened to me once but I don't know why. This is the way I solved it.

Categories

Resources