命令是一种事件处理程序,为什么我的按钮执行命令?

时间:2017-03-24 09:29:23

标签: c# wpf events

我正在学习wpf,代表,事件以及我对什么做了一些线索,但在实施ICommand时我有点迷失

我有一个类实现了ICommand接口,就像这样

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

    public RelayCommand(Action<object> execute) : this (execute, null)
    {

    }

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

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        //throw new NotImplementedException();
        return true;
    }

    public void Execute(object parameter)
    {
        //throw new NotImplementedException();
        this._execute(parameter);
    }

    public void OnCanExecute()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }

然后我的ViewModel使用i。

class PersonViewModel
{
    public ICommand ICommandPresenter { get; set; }
    public PersonModel PM;
    private string _btnString = "";

    #region Propertys
    public string ButtonString
    {
        get {return _btnString; }
        set
        {
            if (_btnString.Equals(value))
            {
                return;
            }

            _btnString = value;
        }
    }
    public string Name { get { return PM.Name; } set
        {
            PM.Name = value;
        }
     }
    #endregion Propertys
    public PersonViewModel()
    {
        PM = new PersonModel();
        ICommandPresenter = new RelayCommand(ChangeName);
    }

    public void ChangeName(object a)
    {
        string s = a as string;
        MessageBox.Show("Hello from PersonViewModel Commander: " + s);
    }
}

这让我感到困惑。在RelayCommand类中,我有一个事件CanExecuteChanged,但该事件从未执行/触发。从我对事件的阅读中所理解的是,你并不“需要”拥有一个事件的订阅者,但是如果你想要一个事件,你至少应该在执行它的代码中的某个地方。但我在我的代码中没有这个,但由于某种原因,我的按钮仍然按照我的命令执行。我仍然明白我点击了按钮,但我的代码中没有订阅该按钮的任何内容。

  • 为什么我的按钮能够执行我的代码,即使我没有连接到它的事件?
  • 由于我没有任何与CanExecuteChanged事件相关联的订阅者,它会变得无用吗?
  • 该命令是否像活动一样?如果是这样,请描述从单击按钮到执行命令的整个过程。

2 个答案:

答案 0 :(得分:0)

CanExecuteChanged是ICommand类的成员,并且简化了一些事情,wpf框架使用它来启用/禁用您的按钮,具体取决于CanExecute()方法的结果。单击按钮时,CanExecute对于您要执行的代码并不紧密,但对于完成合法的条件,CanExecute是不紧的。

Command执行你的代码,因为你在这里发送指向你的方法的指针(ChangeName方法)

  

ICommandPresenter = new RelayCommand(ChangeName);

所以你根本没有使用CanExecuteChange,因为你正在调用这个构造函数:

  

public RelayCommand(Action<object> execute)

要使用CanExecute,您必须调用接受CanExecute谓词的重载构造函数:

  

public RelayCommand(Action<object> execute, Func<object,bool> canExecute)

要调用它,只需传递一个返回bool作为第二个参数的函数:

ICommandPresenter = new RelayCommand(ChangeName, ()=>MyCustomLogicWhenButtonIsActive());

答案 1 :(得分:0)

根据我在.Net的源代码中看到的内容,分配给按钮的Command属性的命令以下列方式执行:

  1. 单击该按钮会调用按钮的OnClick()方法(位于按钮的ButtonBase基类中)。
  2. OnClick()方法(see source here)调用Commands.CommandHelpers.ExecuteCommandSource()方法,将this作为命令源参数传递。
  3. ExecuteCommandSource()see source here)进一步调用CriticalExecuteCommandSource()方法,将相同的命令源作为参数传递。
  4. 最后,CriticalExecuteCommandSource()方法(see source here)访问命令源的Command成员,并且:
    • 检查命令的CanExecute()方法是否返回true
    • 如果是true,则会调用命令的Execute()方法。
  5. (如果您使用RelayCommand实现,那么显然,RelayCommand类会在您实例化时将调用传递给您传递给其构造函数的特定方法。)
  6. 所以,回答你的问题是否通过事件触发命令:

    源指示OnClick()方法直接执行命令,而不是通过事件处理。正如您在源代码中看到的,此方法 引发Click事件,但它与命令执行分开。

    尽管如此,框架首先如何调用OnClick()方法仍然没有答案;我根本不知道。