zoukankan      html  css  js  c++  java
  • MvvmLight学习心得三

    MvvmLight的抽象类ViewModelBase继承了ObservableObject这个类,我们来看看这个类:

     /// <summary>
        /// 一个基类,为了使它的对象属性必须具有可观察性
        /// INotifyPropertyChanged,INotifyPropertyChanging
        /// </summary>
        public class ObservableObject:INotifyPropertyChanged,INotifyPropertyChanging
    

    可以看见其实它继承了INotifyPropertyChanged,INotifyPropertyChanging这两个.net里的接口,在System.dll程序集中:

    #region Assembly System.dll, v2.0.50727
    // C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll
    #endregion
    
    namespace System.ComponentModel
    {
        // Summary:
        //     Notifies clients that a property value has changed.
        public interface INotifyPropertyChanged
        {
            // Summary:
            //     Occurs when a property value changes.
            event PropertyChangedEventHandler PropertyChanged;
        }
    }

    当属性改变时通知客户端。这个类肯定实现了这两个接口中的事件,来看下:

    /// <summary>
            /// 如果需要,唤起PropertyChanged事件,非泛型
            /// </summary>
            /// <remarks>如果参数名在当前类的属性中不一致
            /// 在DEBUG条件下抛出异常VerifyPropertyName中</remarks>
            /// <param name="propertyName">改变的属性名称</param>
            /// <param name="propertyName"></param>
            [SuppressMessage("Microsoft.Design","CA1030:UseEventsWhereAppropriate",
              Justification="This cannot be an event" )]
            protected virtual void RaisePropertyChanged(string propertyName)
            {
                VerifyPropertyName(propertyName);
    
                var handler = PropertyChanged;
                if (handler != null)
                {
                    handler(this, new PropertyChangedEventArgs(propertyName));
                }
            }

    还有个就是

    protected virtual void RaisePropertyChanging(string propertyName)
    参数都是string类型的propertyName.

    那么更好的肯定是实现这两个方法的泛型版本:

    /// <summary>
          /// 如果需要,唤起PropertyChanged事件,泛型
          /// </summary>
          /// <typeparam name="T"></typeparam>
          /// <param name="propertyExpression"></param>
          [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
             Justification = "This cannot be an event")]
          [SuppressMessage(
              "Microsoft.Design",
              "CA1006:GenericMethodsShouldProvideTypeParameter",
              Justification = "This syntax is more convenient(方便) than other alternatives(选择的余地)")]
          protected virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
          {
              var handler = PropertyChanged;
              if (handler != null)
              {
                  var propertyName = GetPropertyName(propertyExpression);
                  handler(this, new PropertyChangedEventArgs(propertyName));
              }
          }

    注意到这里有个GetPropertyName方法:

    /// <summary>
       /// 根据表达式提取(Extract)属性名字
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <param name="propertyExpression"></param>
       /// <returns></returns>
       protected string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
       {
           if (propertyExpression == null)
           {
               throw new ArgumentNullException("propertyExpression");
           }
           //关于Linq的文章,可以参考
           //http://www.cnblogs.com/lifepoem/archive/2011/12/16/2288017.html
           //http://www.cnblogs.com/zhili/archive/2012/12/12/LambdaExpression.html
           var body = propertyExpression.Body as MemberExpression;
           if (body == null)
           {
               throw new ArgumentException("Invalid argument", "propertyExpression");
           }
           
           var property = body.Member as PropertyInfo;
           if (property == null)
           {
               throw new ArgumentException("Argument is not a property","propertyExpression");
           }
    
           return property.Name;
       }

    关于Linq学习的博文,园子里已经有很多人写过了,可以参考lifepoemzhili的。

    这个类还有两个重要的泛型方法,Set<T>:

    /// <summary>
          /// 把新值赋给属性,然后唤起PropertyChanged事件
          /// </summary>
          /// <typeparam name="T">属性类型</typeparam>
          /// <param name="propertyExpression">确认属性改变的表达式,翻译有问题</param>
          /// <param name="field">保存属性值的变量</param>
          /// <param name="newValue">改变过后的新值</param>
          /// <returns>事件只有在两个值不相等的情况下才被唤起</returns>
          protected bool Set<T>(
              Expression<Func<T>> propertyExpression,
              ref T field,
              T newValue)
          {
              if (EqualityComparer<T>.Default.Equals(field,newValue))
              {
                  return false;
              }
    
              RaisePropertyChanging(propertyExpression);
              field = newValue;
              RaisePropertyChanged(propertyExpression);
              return true;
          }

    另外一个其实也就是把Expression<Func<T>>参数换成string参数而已

    protected bool Set<T>(
               string propertyName,
               ref T field,
               T newValue)

    之前我们的例子中的RaisePropertyChanged就是其实就是调用ViewModelBase里的RaisePropertyChanged函数,因为这个函数是虚函数,所以是调用的ViewModelBase中的RaisePropertyChanged实现:

    [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
                Justification = "This cannot be an event")]
            protected virtual void RaisePropertyChanged<T>(string propertyName, T oldValue, T newValue, bool broadcast)
            {
                if (string.IsNullOrEmpty(propertyName))
                {
                    throw new ArgumentException("This method cannot be called with an empty string", "propertyName");
                }
    
                RaisePropertyChanged(propertyName);
    
                if (broadcast)
                {
                    Broadcast(oldValue, newValue, propertyName);
                }
            }

    最后一个参数如果不为true,而且不注册PropertyChanged事件将不会有任何返回结果。下篇我们介绍NotificationMessage和DialogMessage的简单使用

  • 相关阅读:
    C# 动态创建SQL数据库(一)
    在Winform中菜单动态添加“最近使用文件”
    转(C# 类似右键菜单弹出窗体)
    为什么不能用Abort退出线程
    C# GDI绘制波形图
    转(C# 实现生产者消费者队列)
    为字段设置初始值
    闲话资源管理
    正确使用 new 修饰符
    减少装箱与拆箱
  • 原文地址:https://www.cnblogs.com/johnwonder/p/2846749.html
Copyright © 2011-2022 走看看