Errors while using Prisms CommandParameter

Reading stack trace error messages is sometimes just hard!

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.

line9-1

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 :-)