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

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.

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.

XAML Forms not recognizing local and referenced classes

I opened a VS 2012 Solution in VS 2015 and cannot get it to compile. It was originally targeting .Net 3.5 and used the WPF Toolkit, which caused some ambiguous references. I resolved that by removing the reference to the WPF Toolkit and replacing it with the package DotNetProjects.Wpf.Toolkit.
Now I have to tackle the next issue, which I suspect is not caused by the obvious but is a cascade from some other hidden gotcha from upgrading the versions.
My XAML forms are not recognizing the existence of classes within referenced namespaces. I can get them to come up on intellisense but the application won't compile and the error says something like: "The name "MainWindow" does not exist in the namespace "clr-namespace:FieldSheetPrinter".
I have defined my main form with the following:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FieldSheetPrinter"
mc:Ignorable="d"
xmlns:Custom="http://schemas.microsoft.com/netfx/2009/xaml/presentation"
xmlns:validationRules="clr-namespace:SWallTech.ValidationSupport;assembly=SWallTech.ValidationSupport"
xmlns:FieldSheetPrinter_Converters="clr-namespace:FieldSheetPrinter.Converters"
xmlns:Converters="clr-namespace:SWallTech.WPF.Support.Converters;assembly=SWallTech.WPF.Support"
x:Class="FieldSheetPrinter.MainWindow"
x:Name="MainWindow"
Title="CAMRA Field Sheet Printer - Stonewall Technologies, Inc."
Width="744"
Height="583"
WindowStartupLocation="CenterScreen"
Icon="CamraPrint.ico">
I have references to the SWallTech.WPF.Support project, which is in the solution, and the compiler has no problem recognizing the classes in that project's Converters namespace. This code has no error indicator. (Red squiggles.)
<Converters:IntGreaterThanZeroToVisibilityConverter
x:Key="IntGreaterThanZeroToVisibilityConverter" />
<Converters:DatabaseConnectionImageSourceConverter
x:Key="DatabaseConnectionImageSourceConverter" />
However if I try to refer to the ViewModel I am using as the datasource, I get an error:
<local:FieldSheetPrinterViewModel
x:Key="FieldSheetPrinterViewModelDataSource"
d:IsDataSource="True" />
I also get the error that the XAML form itself is not in the namespace FieldSheetPrinter, which of course it is, as you can see from the Code-Behind.
namespace FieldSheetPrinter
{
public partial class MainWindow : Window
...
}
I have tried everything I can think of, and I am truly stumped.
Joey
As suggested above, the problem wasn't directly with the XAML, or at least not completely. The original developer had named the Window tag with the same name as the code-behind class name, and that seems to be prohibited now. That was the only issue with the XAML. Everything else had to do with overlaps in the WPF and Windows.System.Data libraries that caused IValueConverter (in the System.Windows.Data namespace) to go unrecognized. I eliminated any other references that could have conflicted, and corrected some syntax issues in the code-behind that apparently were deprecated.
Ex.
stringVariable.IsNullOrEmpty()
was used instead of
string.IsNullOrEmpty(stringVariable)
In other places some ObservableCollection objects weren't recognized as enumerable, so I had to add "ToList()" before looping through the collection.
Weird, but I didn't write this stuff!
Thanks for the suggestions.
Joey

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>

Problems with adding EnumMatchToBooleanConverter to my xaml file

I am trying to follow this radiobutton tutorial
I created a class called EnumMatchToBooleanConverter and it is in the top level of my wpf project. It says to place the inside a window.resources like this:
<Window.Resources>
<EnumMatchToBooleanConverter x:Key="enumConverter" />
</Window.Resources>
I am using it in a usercontrol so I have placed it inside a stackpanel instead:
<StackPanel.Resources>
<EnumMatchToBooleanConverter x:Key="enumConverter" />
</StackPanel.Resources>
I have Microsoft Visual Studio Ultimate 2012 and it gives me an error:
EnumMatchToBooleanConverter is not supported in a Windows Presentation Foundation (WPF) project.
Any ideas as to what I am doing wrong? Am I not allowed to place it inside a stackpanel.resources?
I just tried placing it inside a grid.resources
<Grid.Resources>
<EnumMatchToBooleanConverter x:Key="enumConverter" />
</Grid.Resources>
and it says
The type 'EnumMatchToBooleanConverter' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.
Well it is in the same namespace as the rest of my project, so I'm unsure why it isn't finding it.
Change
<EnumMatchToBooleanConverter x:Key="enumConverter" />
for
<local:EnumMatchToBooleanConverter x:Key="enumConverter" />
All non-built-in classes you reference in XAML must be prefixed by their corresponding xmlns prefix.
HighCore's got it right. Just to add to this namespace discussion, I thought I'd point out another approach that can help make the code more readable or help you diagnose where certain Controls/Value Converters/etc are coming from (i.e., which assembly they are really coming from). This technique could allow your XAML to appear like Christian has it in his blog (without the xmlns prefix):
<EnumMatchToBooleanConverter x:Key="enumConverter" />
Essentially you perform some some namespace mappings to consolidate namespaces like this (only works if the files are in a different assembly/project). So in my example above you have mapped one of your namespaces to the default xmlns, so you would not need any prefix in the XAML.
I'm still trying to figure out how far to take this technique and Paul Stovell talks about taking it to the extreme, like I've shown above.
Even if you don't end up applying it to that degree, knowing about it might come in handy if you're looking at someone else's Xaml and they have applied a mapping like that. Knowing that would remind you to lookup the AssemblyInfo.cs file and check for the mapping and possibly help you track down where a Control/Value Converter/etc is actually located.

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

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>

Categories

Resources