为什么必须公开ICommand对象才能在WPF中正常工作?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么必须公开ICommand对象才能在WPF中正常工作?相关的知识,希望对你有一定的参考价值。

我正在关注Pluralsight的一门名为“实用MVVM”的课程。在本课程的第4单元中,作者解释了如何使用命令,当我遇到这个奇怪的问题时。我写了几乎与视频中相同的代码,除了一个区别。我当地的ICommand变量被宣布为private而不是public

当我单击具有绑定设置的按钮时,会发生以下情况:属于EditCoffee()命令的方法EditCommand

  • ICommand EditCommand被宣布为公共或内部时,方法EditCoffee()Execute()类中执行CanExecute()CustomCommand后执行。
  • ICommand EditCommand被声明为私有或受保护时,方法EditCoffee()永远不会被执行,并且不会在Execute()类中执行CanExecute()CustomCommand

值得一提的是,LoadCommands()在两种情况下均被触发。

CoffeeOverviewViewModel:

using JoeCoffeeStore.StockManagement.App.Services;
using JoeCoffeeStore.StockManagement.App.Utility;
using JoeCoffeeStore.StockManagement.Model;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace JoeCoffeeStore.StockManagement.App.ViewModel
{
    public class CoffeeOverviewViewModel : INotifyPropertyChanged
    {
        // INotifyPropertyChanged implementation   
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged([CallerMemberName]string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }      

        // Commands   
        private ICommand EditCommand { get; set; }           

        // Data Service
        private CoffeeDataService _coffeeDataService;

        // Properties
        private ObservableCollection<Coffee> _coffees;    
        public ObservableCollection<Coffee> Coffees
        {
            get{ return _coffees; }
            set
            {
                _coffees = value;
                OnPropertyChanged();
            }
        }

        private Coffee _selectedCoffee;    
        public Coffee SelectedCoffee
        {
            get { return _selectedCoffee; }
            set
            {
                _selectedCoffee = value;
                OnPropertyChanged();
            }
        }

        // Constructor
        public CoffeeOverviewViewModel()
        {
            _coffeeDataService = new CoffeeDataService();
            LoadData();    
            LoadCommands();
        }


        private void LoadCommands()
        {
            EditCommand = new CustomCommand(EditCoffee, CanEditCoffee);
        }

        private void EditCoffee(object obj)
        {                
            //TODO
        }

        private bool CanEditCoffee(object obj)
        {
            if (SelectedCoffee != null)
                return true;
            return false;    
        }

        private void LoadData()
        {
            Coffees = new ObservableCollection<Coffee>(_coffeeDataService.GetAllCoffees());
        }
    }
}

CustomCommand.cs:

using System;
using System.Windows.Input;

namespace JoeCoffeeStore.StockManagement.App.Utility
{
    public class CustomCommand : ICommand
    {
        private Action<object> _execute;
        private Predicate<object> _canExecute;

        public CustomCommand(Action<object> execute, Predicate<object> canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

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

        public bool CanExecute(object parameter)
        {
            bool b = _canExecute == null ? true : _canExecute(parameter);
            return b;
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

CoffeeOverviewView.xaml:

<StackPanel Grid.Row="7">
    <Button  Command="{Binding EditCommand}" Content="Edit coffee"/>
</StackPanel>

解决方案结构

enter image description here

答案

绑定不是魔术。它的代码采用您的XAML绑定声明:

 <Button  Command="{Binding EditCommand}"

并在类的DataContext中查找该名称的属性EditCommand

您的XAML视图是一个与ViewModel不同的类,因此它只能访问ViewModel上的公共属性。甚至内部属性都超出范围,因为它是试图在WPF库中访问它的绑定代码,而不是您自己的视图代码。

以上是关于为什么必须公开ICommand对象才能在WPF中正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

利刃 MVVMLight 6:命令基础

2022-03-23 WPF面试题 WPF中的命令设计模式和ICommand是什么?

2022-03-23 WPF面试题 WPF中的命令设计模式和ICommand是什么?

如何在 WPF 中使用 ICommand 中的 CanExecute 方法

wpf mvvm模式 Icommand接口应该如何理解?

WPF 自定义快捷键命令(COMMAND)(转)