CS0201 error in ICommand impmentation for WPF application

混江龙づ霸主 提交于 2021-01-29 08:27:15

问题


I develop a WPF application, obviously, I use MVVM pattern. Without an external library (MvvmCross, MvvmLight, ...)

And I've tried to implement ICommand:

Option 1

public class Command : ICommand
{
    private readonly Func<bool> _canExecute;
    private readonly Action _action;

    public Command1(Action action, Func<bool> canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter) => true;

    public void Execute(object parameter) => _action();
}

Option 2

public class Command : ICommand
{
    private readonly Func<bool> _canExecute;
    private readonly Action<object> _action;

    public Command1(Action<object> action, Func<bool> canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter) => true;

    public void Execute(object parameter) => _action(parameter);
}

Option 3

...with some delegates

public class Command : ICommand
{
    private readonly Func<object, bool> _canExecute;
    private readonly Action<object> _execute;

    public Command(Action<object> execute) => _execute = execute ?? throw new ArgumentNullException(nameof(execute));

    public Command(Action execute)
        : this((Action<object>)delegate { execute(); })
    {
        if (execute == null)
        {
            throw new ArgumentNullException(nameof(execute));
        }
    }

    public Command(Action<object> execute, Func<object, bool> canExecute)
        : this(execute) => _canExecute = canExecute ?? throw new ArgumentNullException(nameof(canExecute));

    public Command(Action execute, Func<bool> canExecute)
        : this(delegate
        {
            execute();
        }, (object o) => canExecute())
    {
        if (execute == null)
        {
            throw new ArgumentNullException(nameof(execute));
        }
        if (canExecute == null)
        {
            throw new ArgumentNullException(nameof(canExecute));
        }
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter) => _canExecute != null ? _canExecute(parameter) : true;

    public void Execute(object parameter) => _execute(parameter);
}

In all cases:

public class MainViewModel : BaseViewModel
{
    public ICommand MyCommand = new Command(() => MyVoid());
    private void MyVoid()
    {
        // do something
    }
}
public class MainViewModel : BaseViewModel
{
    public ICommand MyCommand = new Command(MyVoid);
    private void MyVoid()
    {
        // do something
    }
}

I've a CS0201 error (Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement).

I don't understand why.

In other projects, which use MVVM pattern (Xamarin.Forms, Xamarin, ...), I use Xamarin.Forms.Command or MvxCommand (MvvmCross) and it works...


回答1:


I don't suggest to name the realying class Command because you may get naming conflict with some built-in classes.

The closest to your try code:

public ICommand MyCommand => new Command(parameter => { MyVoid(); });

or the same in "block" syntax

public ICommand MyCommand
{
    get
    {
        return new Command(parameter => { MyVoid(); });
    }
}

But it's wrong approach because it will create new Command instance each time the command was called. Give to Garbage Collector as less work as possible. Examples of the correct ways doing it you may find below.

You're developing another bicycle. :) Look here.

Here is copy-paste from my project. It's exactly the same as in above link.

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
    public void Execute(object parameter) => _execute(parameter);
}

And the usage

<Button Contecnt="Click me!" Command="{Binding MyCommand}"/>
private ICommand _myCommand;

public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
    // do here the execution
}));

And with parameter (Binding for CommandParameter is available too)

<Button Contecnt="Click me!" Command="{Binding MyCommand}" CommandParameter="test value"/>
public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
    if (parameter is string p && p == "test value")
    {
        // do here the execution
    }
}));

And finally, usage of optional CanExecute

public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
    // do here the execution
    // don't put the same condition as in CanExecute here,
    // it was already checked before execution has entered this block
},
parameter => (x > y) && (a + b > c) // any condition or just return a bool
));

if CanExecute returns false, the command will not be executed and Button or MenuItem becomes automatically disabled. Just test it.



来源:https://stackoverflow.com/questions/61463227/cs0201-error-in-icommand-impmentation-for-wpf-application

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!