zoukankan      html  css  js  c++  java
  • WPF 手动实现 INotifyPropertyChanged 和 ICommand

    查看 INotifyPropertyChanged 接口源码

    namespace System.ComponentModel
    {
        //
        // 摘要:
        //     Notifies clients that a property value has changed.
        public interface INotifyPropertyChanged
        {
            //
            // 摘要:
            //     Occurs when a property value changes.
            event PropertyChangedEventHandler PropertyChanged;
        }
    }

    INotifyPropertyChanged接口定义了一个属性改变处理事件,通知客户端这个属性值已经发生改变。

    定义NotifyObject实现 INotifyPropertyChanged

        public class NotifyObject : INotifyPropertyChanged
        {
            /// <summary>
            /// Occurs when a property value changes.
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
    
            /// <summary>
            /// Checks if a property already matches a desired value. Sets the property and
            /// notifies listeners only when necessary.
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="storage"></param>
            /// <param name="value"></param>
            /// <param name="propertyName"></param>
            /// <returns></returns>
            protected virtual bool SetProperty<T>(ref T storage,T value,[CallerMemberName] string propertyName=null)
            {
                if (EqualityComparer<T>.Default.Equals(storage, value)) return false;
    
                storage = value;
    
                RaisePropertyChanged(propertyName);
    
                return true;
            }
    
            /// <summary>
            /// Raises this object's PropertyChanged event.
            /// </summary>
            /// <param name="propertyName"></param>
            protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    通过SetProperty<T>泛型方法 可以接收任意类型的属性,然后判断属性值是否发生变化,如果变化就触发PropertyChanged事件,通知UI本属性值已经发生改变。

    查看ICommand源码

    namespace System.Windows.Input
    {
        //
        // 摘要:
        //     Defines a command.
        public interface ICommand
        {
            //
            // 摘要:
            //     Occurs when changes occur that affect whether or not the command should execute.
            event EventHandler CanExecuteChanged;
    
            //
            // 摘要:
            //     Defines the method that determines whether the command can execute in its current
            //     state.
            //
            // 参数:
            //   parameter:
            //     Data used by the command. If the command does not require data to be passed,
            //     this object can be set to null.
            //
            // 返回结果:
            //     true if this command can be executed; otherwise, false.
            bool CanExecute(object parameter);
            //
            // 摘要:
            //     Defines the method to be called when the command is invoked.
            //
            // 参数:
            //   parameter:
            //     Data used by the command. If the command does not require data to be passed,
            //     this object can be set to null.
            void Execute(object parameter);
        }
    }
    

    ICommand接口定义了一个普通的事件,和命令执行方法Execute()、命令是否可以执行方法CanExecute()

    定义DelegateCommand实现 ICommand

    public class DelegateCommand : ICommand
        {
            public event EventHandler CanExecuteChanged;
            private readonly Action _executeMethod;
            private readonly Func<bool> _canExecuteMethod;
    
            /// <summary>
            /// Creates a new instance of DelegateCommand with the Action to invoke on execution.
            /// </summary>
            /// <param name="executeMethod"></param>
            public DelegateCommand(Action executeMethod)
                : this(executeMethod, () => true)
            {
    
            }
    
            /// <summary>
            /// Creates a new instance of DelegateCommand with the Action to invoke on execution
            /// and a Func to query for determining if the command can execute.
            /// </summary>
            /// <param name="executeMethod"></param>
            /// <param name="canExecuteMethod"></param>
            public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod)
            {
                if(executeMethod==null||canExecuteMethod==null)
                    throw  new ArgumentNullException(nameof(executeMethod));
                _executeMethod = executeMethod;
                _canExecuteMethod = canExecuteMethod;
            }
    
            /// <summary>
            /// Executes the command.
            /// </summary>
            /// <param name="parameter"></param>
            public void Execute(object parameter)
            {
                _executeMethod();
            }
    
            /// <summary>
            /// Determines if the command can be executed.
            /// </summary>
            /// <param name="parameter"></param>
            /// <returns></returns>
            public bool CanExecute(object parameter)
            {
                return _canExecuteMethod();
            }
        }
    

    通过DelegateCommand构造函数加载两个委托(Action _executeMethod ,Func<bool> _canExecuteMethod),如果存在可以正常实现命令,这里ICommand的实现也是极简模式,后面可以继续扩展。

    在ViewModel中使用NotifyObject和DelegateCommand

        public class MainWindowViewModel:NotifyObject
        {
            /// <summary>
            /// 输入1
            /// </summary>
            private double _input1;
            public double Input1
            {
                get => _input1;
                set => SetProperty(ref _input1,value);
            }
    
            /// <summary>
            /// 输入2
            /// </summary>
            private double _input2;
            public double Input2
            {
                get => _input2;
                set => SetProperty(ref _input2, value);
            }
    
            /// <summary>
            /// 结果
            /// </summary>
            private double _result;
            public double Result
            {
                get => _result;
                set => SetProperty(ref _result, value);
            }
    
            /// <summary>
            /// 加法命令
            /// </summary>
            public DelegateCommand _addCommand;
            public DelegateCommand AddCommand => _addCommand ??= new DelegateCommand(Add);
            private  void Add()
            {
                Result = Input1+Input2;
            }
        }
    

    在ViewModel 定义Input1 Input2 Result 跟View中的控件进行数据绑定,定义AddCommand跟View中事件拥有者绑定(命令绑定),当UI界面点击加法按钮,事件处理器就会响应这个命令执行Add()方法,完成运算。

    总结:

    通过上述接口实现,简单可以实现数据绑定和命令绑定,这个思路主要借鉴Prism框架,也是一个学习过程记录。

  • 相关阅读:
    Eclipse 远程调试
    大数据处理方法bloom filter
    sicily 1259 Sum of Consecutive Primes
    sicily 1240. Faulty Odometer
    sicily 1152 简单马周游 深度优先搜索及回溯算法
    sicily 1050 深度优先搜索解题
    sicily 1024 邻接矩阵与深度优先搜索解题
    sicily 1156 二叉树的遍历 前序遍历,递归,集合操作
    sicily 1443 队列基本操作
    sicily 1006 team rankings 枚举解题
  • 原文地址:https://www.cnblogs.com/YourDirection/p/14266205.html
Copyright © 2011-2022 走看看