CanExecute on RelayCommand<T> not working

It seems that the RelayCommand will cast the value the parameter to the generic T.

But you cannot cast a null to a struct, as the exception tells you!

If you initialize the RelayCommand with a nullable struct, it will work as expected!

RelayCommand<int?> or RelayCommand<Nullable<int>>

HTH


Arcturus was correct in identifying what the problem was, however I didn't like the solution of using nullable primitives. I personally don't like nullable primitives unless I have a very good reason to use them.

Instead, I changed the implementation of RelayCommand as follows:

    bool ICommand.CanExecute(object parameter)
    {
        if (parameter == null && typeof(T).IsValueType)
        {
            return CanExecute(default(T));
        }
        return CanExecute((T)parameter);
    }

I didn't make this same change for the generic Execute method (at least for now) because I don't think it is unreasonable to fail in that case if the command really does expect an argument.

The problem with CanExecute is that the WPF system will sometimes call it before certain bindings can be evaluated. For example:

        <Button Content="Fit To Width" Command="{Binding Path=FitToWidthCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualWidth}" />
        <Button Content="Fit To Height" Command="{Binding Path=FitToHeightCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualHeight}" />

In the above XAML, you notice the command parameter is bound to the actual width of a control. However, WPF will call CanExecute on the button's command before the "imageScrollViewer" control is necessarily laid out/rendered - so there is no actual width/height. By the time the user clicks the button and Execute is invoked, of course the control is laid out so values get sent to the command. If not - I think failing is what should be expected - but only when the user actually clicks the button.

Of course I don't like the different behavior of CanExecute and Execute, but for now it seems to fit within the restrictions presented by the framework. I may find a scenario where this causes me grief, but I've been liking the change so far.