12. February 2020
Errors while using Prisms CommandParameter
While using Prism DelegateCommand and CommandParameter I hit two errors that I had to spent some time finding out what really meant.
I had to do some trial and error stuff (commenting out code) until I figured it out.
I sometime wish the errors in Xamarin would be easier to digest. It would be lovely if the team could do something! Even something like Ben.Demystifier that I use for all my personal try/catch errors.
The first error
I got this runtime error and like you can see its a “Specified cast is not valid” error.
$exception {System.InvalidCastException: Specified cast is not valid.
at (wrapper castclass) System.Object.__castclass_with_cache(object,intptr,intptr)
at Prism.Commands.DelegateCommand`1[T].CanExecute (System.Object parameter) [0x00000] in d:\a\1\s\Source\Prism\Commands\DelegateCommand{T}.cs:113
at Prism.Commands.DelegateCommandBase.System.Windows.Input.ICommand.CanExecute (System.Object parameter) [0x00000] in d:\a\1\s\Source\Prism\Commands\DelegateCommandBase.cs:67
at Xamarin.Forms.MenuItem.OnCommandParameterChanged () [0x00009] in D:\a\1\s\Xamarin.Forms.Core\MenuItem.cs:128
at Xamarin.Forms.MenuItem+<>c.<.cctor>b__46_2 (Xamarin.Forms.BindableObject bo, System.Object o, System.Object n) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\MenuItem.cs:16
at Xamarin.Forms.BindableObject.SetValueActual (Xamarin.Forms.BindableProperty property, Xamarin.Forms.BindableObject+BindablePropertyContext context, System.Object value, System.Boolean currentlyApplying, Xamarin.Forms.Internals.SetValueFlags attributes, System.Boolean silent) [0x00120] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:463
at Xamarin.Forms.BindableObject.SetValueCore (Xamarin.Forms.BindableProperty property, System.Object value, Xamarin.Forms.Internals.SetValueFlags attributes, Xamarin.Forms.BindableObject+SetValuePrivateFlags privateAttributes) [0x00173] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:397
at Xamarin.Forms.BindingExpression.ApplyCore (System.Object sourceObject, Xamarin.Forms.BindableObject target, Xamarin.Forms.BindableProperty property, System.Boolean fromTarget) [0x00220] in D:\a\1\s\Xamarin.Forms.Core\BindingExpression.cs:156
at Xamarin.Forms.BindingExpression.Apply (System.Object sourceObject, Xamarin.Forms.BindableObject target, Xamarin.Forms.BindableProperty property) [0x0006b] in D:\a\1\s\Xamarin.Forms.Core\BindingExpression.cs:71
at Xamarin.Forms.Binding.Apply (System.Object context, Xamarin.Forms.BindableObject bindObj, Xamarin.Forms.BindableProperty targetProperty, System.Boolean fromBindingContextChanged) [0x0006d] in D:\a\1\s\Xamarin.Forms.Core\Binding.cs:136
at Xamarin.Forms.BindableObject.ApplyBindings (System.Boolean skipBindingContext, System.Boolean fromBindingContextChanged) [0x00041] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:480
at Xamarin.Forms.BindableObject.SetInheritedBindingContext (Xamarin.Forms.BindableObject bindable, System.Object value) [0x0005a] in D:\a\1\s\Xamarin.Forms.Core\BindableObject.cs:209
at Xamarin.Forms.Element.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00000] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:505
at Xamarin.Forms.TemplatedPage.SetChildInheritedBindingContext (Xamarin.Forms.Element child, System.Object context) [0x00008] in D:\a\1\s\Xamarin.Forms.Core\TemplatedPage.cs:38
at Xamarin.Forms.Element.set_Parent (Xamarin.Forms.Element value) [0x000d2] in D:\a\1\s\Xamarin.Forms.Core\Element.cs:197
at Xamarin.Forms.Page.OnToolbarItemsCollectionChanged (System.Object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args) [0x00022] in D:\a\1\s\Xamarin.Forms.Core\Page.cs:496
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedEventArgs e) [0x00018] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs:263
at System.Collections.ObjectModel.ObservableCollection`1[T].OnCollectionChanged (System.Collections.Specialized.NotifyCollectionChangedAction action, System.Object item, System.Int32 index) [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs:338
at System.Collections.ObjectModel.ObservableCollection`1[T].InsertItem (System.Int32 index, T item) [0x0001a] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corefx/src/System.ObjectModel/src/System/Collections/ObjectModel/ObservableCollection.cs:196
at System.Collections.ObjectModel.Collection`1[T].Add (T item) [0x00020] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/external/corefx/src/Common/src/CoreLib/System/Collections/ObjectModel/Collection.cs:71
at MyViewModelPage.InitializeComponent () [0x00012] in C:\...\obj\Debug\netstandard2.0\Views\MyViewModelPage.xaml.g.cs:22
at MyViewModelPage..ctor () [0x00008] in C:\...\Views\MyViewModelPage.xaml.cs:9
at (wrapper managed-to-native) System.Reflection.RuntimeConstructorInfo.InternalInvoke(System.Reflection.RuntimeConstructorInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00005] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:936 } System.InvalidCastException
But what was thowing it?
At the botom you can see “MyViewModelPage.xaml.cs:9”
But there is nothing there that gives a hint on what is causing the error.
Do you know what the problem is?
So
What I discovered (with some trial and error) was that I had the following code in my XAML where I had changed Profile.Id to be an int.
<ToolbarItem Command="{Binding DeleteProfileCommand}" CommandParameter="{Binding Profile.Id}">
with this delegate command.
public DelegateCommand<string> DeleteProfileCommand { get; }
In my mocked object I had set Id as a string. And now just navigating to this view caused the error.
When I figured it out I just swapped string out for int.
public DelegateCommand<int> DeleteProfileCommand { get; }
now I could surely continue my work…
…but think again
Second error hit
{System.InvalidCastException: T for DelegateCommand<T> is not an object nor Nullable.
at Prism.Commands.DelegateCommand`1[T]..ctor (System.Action`1[T] executeMethod, System.Func`2[T,TResult] canExecuteMethod) [0x0005d] in d:\a\1\s\Source\Prism\Commands\DelegateCommand{T}.cs:68
at Prism.Commands.DelegateCommand`1[T]..ctor (System.Action`1[T] executeMethod) [0x00000] in d:\a\1\s\Source\Prism\Commands\DelegateCommand{T}.cs:44
at MyViewModel..ctor (Prism.Navigation.INavigationService navigationService, ...Interface.IDataService dataService, Prism.Services.Dialogs.IDialogService dialogService) [0x00029] in C:\..\Views\MyViewPageViewModel.cs:54
at (wrapper managed-to-native) System.Reflection.RuntimeConstructorInfo.InternalInvoke(System.Reflection.RuntimeConstructorInfo,object,object[],System.Exception&)
at System.Reflection.RuntimeConstructorInfo.InternalInvoke (System.Object obj, System.Object[] parameters, System.Boolean wrapExceptions) [0x00005] in /Users/builder/jenkins/workspace/archive-mono/2019-08/android/release/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs:936 }
OK I needed to pass an int with the DelegateCommand and int isn’t an object. Its a value type!
What to do!
This was fairly easy to fix. Just use the nullable ‘?’ and Voila!
public DelegateCommand<int?> DeleteProfileCommand { get; }
But brother, I wish the errors could be easier to work though sometimes.
Just to note I got this working in like 10 minutes… but 10 minutes I could have done more work and not spent 60 min preparing this blog post :-)