1

I have problem with passing CommandParameter to my Command

I have command:

private Command<Boolean> _setAsCompletedCommand;
public Command<Boolean> SetAsCompletedCommand
{
    get
    {
        return _setAsCompletedCommand ?? (_setAsCompletedCommand = new Command<Boolean>(isToComplete =>
        {
            if (isToComplete)
            {
                //do something
            }
            else
            {
                //do something else
            }
        }, isToComplete =>
        {
            if (isToComplete)
            {
                //check something
            }
            else
            {
                //check something else
            }

        }));
    }
}

and I'm trying to pass system:Boolean like this:

<Button
    Command="{Binding SetAsCompletedCommand}">
    <Button.CommandParameter>
        <system:Boolean>
            True
        </system:Boolean>
    </Button.CommandParameter>
</Button>

The problem is that on construction of a View my SetAsCompletedCommand.CanExecute() is executed with False parameter.

How is it possible? How can I fix it?

When I click the button CommandParameter is set properly to True

I'm using Catel framework as a MVVM framework in this project. But I don't think it produces the problem.

Tomasz
  • 2,051
  • 3
  • 31
  • 64
  • Check without this framework if this Boolean paramater is passed properly or not ? – AnjumSKhan Nov 29 '15 at 15:15
  • I have checked Boolean parameter is passed correctly in normal case without any framework. Check your logic plz. – AnjumSKhan Nov 29 '15 at 15:30
  • This really sounds like the same problem as [WPF CommandParameter is NULL first time CanExecute is called](https://stackoverflow.com/questions/335849/wpf-commandparameter-is-null-first-time-canexecute-is-called) – StayOnTarget Sep 09 '22 at 21:08

2 Answers2

1

This is very tricky and is caused by the order of binding execution. As soon as the binding updates, WPF runs the CanExecute on your command. At this stage the CommandParameter isn't bound yet and Catel uses the default value of a Boolean (which is false) to use as the command parameter.

After that, commands are only being re-evaluated when a property changes. For example, there is no reason for Catel to invalidate the commands state unless a property changes.

One solution to fix this is to use CommandManager.InvalidateCommands(true) in the InitializeAsync of your view model. This will invalidate the state of all commands on the vm and re-evaluate them (and at this stage, the binding for the command parameter is correct).

You might ask yourself: "Why don't you re-evaluate automatically in the initialize method?".

Well, we did in the past, but we wanted to provide better performance out of the box. This is probably the first time you are using a command parameter that hits this restriction, but I think you created many more commands in the past. It means that you had a performance improvements on all the other commands so far, so I still think it's a good decision. There are sufficient workarounds as well to get back the old behavior where it used the CommandManager of WPF to re-evaluate commands on nearly every routed event (mouse move, keyboard, etc).

Geert van Horrik
  • 5,689
  • 1
  • 18
  • 32
0

To start, I wouldn't ever create a property this way. You should stick to simple properties and let the command itself do all the work. I would suggest writing a custom command and have it inherit from a command base class like this one:

using System;
using System.Windows.Input;

namespace MyCommands
{
    /// <summary>
    /// Base class for all Commands.
    /// </summary>
    public abstract class CommandBase : ICommand
    {
        /// <summary>
        /// Defines the method that determines whether the command can execute in its current 
        /// state.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data 
        /// to be passed, this object can be set to null.</param>
        /// <returns>
        /// true if this command can be executed; otherwise, false.
        /// </returns>
        public virtual bool CanExecute(object parameter) 
        {
            return true;
        }

        /// <summary>
        /// Defines the method to be called when the command is invoked.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data 
        /// to be passed, this object can be set to null.</param>
        public virtual void Execute(object parameter) {}

        /// <summary>
        /// Occurs when changes occur that affect whether or not the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

For there, you can specify the conditions that allow your command to execute and what it should do when it is executed by simply overriding CanExecute and Execute respectively.

Xcalibur37
  • 2,305
  • 1
  • 17
  • 20
  • CommandManager.RequerySuggested might look good on a small app, but it can have a *huge* performance impact on larger applications where you have a lot of commands (they are all being re-evaluated on nearly every mouse move). I don't recommend going this way, although it indeed "fixes" the issue. – Geert van Horrik Nov 30 '15 at 08:11
  • I can't say I have seen this issue in Enterprise implementations. I determined this setup from Microsoft demonstrations in the past. – Xcalibur37 Nov 30 '15 at 15:53