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框架,也是一个学习过程记录。

  • 相关阅读:
    “幽默也能挣钱”:学会把幽默运用在企业管理中
    能不能再爱一回
    好文章,转贴 与爱好写诗的同道共享(转载)
    你是我生命中永恒的歌
    失败后的激励
    充满竞争和不确定性:卓越领导者所应具备的五大美德
    追求成功人生:不可或缺的人生智慧“九商”
    中国草根创业指南针项目京城启动(转载)
    与你一起走过的日子
    《成功长青》作者告诉你有钱人怎么想
  • 原文地址:https://www.cnblogs.com/YourDirection/p/14266205.html
Copyright © 2011-2022 走看看