MVVMFouncation-Code_Through

Revit 高效二次开发的探索(一)

探索应用MVVM模式到Revit二开中,发挥WPF的优势

  • 核心代码Model基类:ObservableObject

     using System;
     using System.ComponentModel;
     using System.Diagnostics;
     namespace MvvmFoundation.Wpf
    {
         /// 具有属性变化通知功能的抽象基类.  
         public abstract class ObservableObject : INotifyPropertyChanged
         {
             protected ObservableObject(){ }
             
             //触发属性变化事件
             protected void RaisePropertyChanged(string propertyName)
             {
                 this.VerifyPropertyName(propertyName);
                 PropertyChangedEventHandler handler = this.PropertyChanged;
                 if (handler != null)
                 {
                     var e = new PropertyChangedEventArgs(propertyName);
                     handler(this, e);
                 }
             }
             
             // DEBUG 条件编译下具有的函数
             [Conditional("DEBUG")]
             [DebuggerStepThrough]
             public void VerifyPropertyName(string propertyName)
             {
     	        // 同时所有属性发生更新
                 if (String.IsNullOrEmpty(propertyName))
                     return;
    
                 // 验证当前对象特定属性的有效性
                 if (TypeDescriptor.GetProperties(this)[propertyName] == null)
                 {//这里的TypeDescriptor实现的功能类似于Reflection出实例的“propertyName”标识的属性
                     string msg = "Invalid property name: " + propertyName;
                     if (this.ThrowOnInvalidPropertyName)
                         throw new ArgumentException(msg);
                     else
                         Debug.Fail(msg);
                 }
             }
             
             //子类重写此属性,可以控制VerifyPropertyName方法中在属性无效时的操作
             protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
             
             //属性变化触发的具体事件活动
             public event PropertyChangedEventHandler PropertyChanged;
         }
    }
    
  • 属性变化事件的监听器:使用观察者模式,在属性对象修改时,自动通知依赖它的对象。

     	 using System;
         using System.Collections.Generic;
         using System.ComponentModel;
         using System.Diagnostics;
         using System.Linq;
         using System.Linq.Expressions;
         using System.Reflection;
         using System.Windows;
         namespace MvvmFoundation.Wpf
         {
     	    public class PropertyObserver : IWeakEventListener
     	        where TPropertySource : INotifyPropertyChanged
     	    {	      
     	        //创建特定类型的属性观察器
     	        public PropertyObserver(TPropertySource propertySource)
     	        {
     	            if (propertySource == null)
     	                throw new ArgumentNullException("propertySource");
     	            //使用弱引用,便于垃圾回收期回收
     	            _propertySourceRef = new WeakReference(propertySource);
     	            _propertyNameToHandlerMap = new Dictionary>();
     	        }
    
     	        // 在观察器中注册事件,而不是在Model类中
     	        public PropertyObserver RegisterHandler(
     	            Expression> expression,
     	            Action handler)
     	        {
     	            if (expression ==  null)
     	                throw new ArgumentNullException("expression");
     				//解析Lambda对象获得属性名
     	            string propertyName = GetPropertyName(expression);
     	            if (String.IsNullOrEmpty(propertyName))
     	                throw new ArgumentException("'expression' did not provide a property name.");
    
     	            if (handler == null)
     	                throw new ArgumentNullException("handler");
     				// this.GetPropertySource() 获得弱引用的引用对象,即依赖于属性的对象
     	            TPropertySource propertySource = this.GetPropertySource();
     	            if (propertySource != null)
     	            {
     	                Debug.Assert(!_propertyNameToHandlerMap.ContainsKey(propertyName), "Why is the '" + propertyName + "' property being registered again?");
    
     	                _propertyNameToHandlerMap[propertyName] = handler;
     	                //将事件添加到 弱引用类的事件管理器 ,PropertyChangedEventManager静态类
     	                PropertyChangedEventManager.AddListener(propertySource, this, propertyName);
     	            }
    
     	            return this;
     	        }
    
     	      // 注销事件,注册的逆过程,与注册类似
     	        public PropertyObserver UnregisterHandler(Expression> expression)
     	        {
     	            if (expression == null)
     	                throw new ArgumentNullException("expression");
    
     	            string propertyName = GetPropertyName(expression);
     	            if (String.IsNullOrEmpty(propertyName))
     	                throw new ArgumentException("'expression' did not provide a property name.");
     			   
     	             TPropertySource propertySource = this.GetPropertySource();
     	             if (propertySource != null)
     	             {
     	                 if (_propertyNameToHandlerMap.ContainsKey(propertyName))
     	                 {
     	                     _propertyNameToHandlerMap.Remove(propertyName);
     	                     PropertyChangedEventManager.RemoveListener(propertySource, this, propertyName);
     	                 }
     	             }
     	            return this;
     	        }
    
     	       
     			// 触发事件,私有方法
     	        bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
     	        {
     	            bool handled = false;
    
     	            if (managerType == typeof(PropertyChangedEventManager))
     	            {
     	                PropertyChangedEventArgs args = e as PropertyChangedEventArgs;
     	                if (args != null && sender is TPropertySource)
     	                {
     	                    string propertyName = args.PropertyName;
     	                    TPropertySource propertySource = (TPropertySource)sender;
    
     	                    if (String.IsNullOrEmpty(propertyName))
     	                    {
     	                     
     	                        foreach (Action handler in _propertyNameToHandlerMap.Values.ToArray())
     	                            handler(propertySource);
    
     	                        handled = true;
     	                    }
     	                    else
     	                    {
     	                        Action handler;
     	                        if (_propertyNameToHandlerMap.TryGetValue(propertyName, out handler))
     	                        {
     	                            handler(propertySource);
     	                            handled = true;
     	                        }
     	                    }
     	                }
     	            }
     	            return handled;
     	        }
     	       
     	       //解析Lambda对象获得属性名
     	        static string GetPropertyName(Expression> expression)
     	        {
     	            var lambda = expression as LambdaExpression;
     	            MemberExpression memberExpression;
     	            if (lambda.Body is UnaryExpression)
     	            {
     	                var unaryExpression = lambda.Body as UnaryExpression;
     	                memberExpression = unaryExpression.Operand as MemberExpression;
     	            }
     	            else
     	            {
     	                memberExpression = lambda.Body as MemberExpression;
     	            }
    
     	            Debug.Assert(memberExpression != null, "Please provide a lambda expression like 'n => n.PropertyName'");
    
     	            if (memberExpression != null)
     	            {
     	                var propertyInfo = memberExpression.Member as PropertyInfo;
    
     	                return propertyInfo.Name;
     	            }
     	            return null;
     	        }
    
     			// 获得依赖于属性的对象,即构造函数中传入的TPropertySource的具体实现类
     	        TPropertySource GetPropertySource()
     	        {
     	            try
     	            {
     	                return (TPropertySource)_propertySourceRef.Target;
     	            }
     	            catch 
     	            {
     	                return default(TPropertySource);
     	            }
     	        }
    
     	        readonly Dictionary> _propertyNameToHandlerMap;
     	        readonly WeakReference _propertySourceRef;      
     	    }
     	}
    
  • 依赖命令RelayCommand类, RelayCommand 类
    和我们自己实现的ICommand接口类似,不做介绍。

     using System;
     using System.Diagnostics;
     using System.Windows.Input;
    
     namespace MvvmFoundation.Wpf
     {
         /// 
         /// A command whose sole purpose is to 
         /// relay its functionality to other
         /// objects by invoking delegates. The
         /// default return value for the CanExecute
         /// method is 'true'.
         /// 
         public class RelayCommand : ICommand
         {
             #region Constructors
    
             public RelayCommand(Action execute)
                 : this(execute, null)
             {
             }
    
             /// 
             /// Creates a new command.
             /// 
             /// The execution logic.
             /// The execution status logic.
             public RelayCommand(Action execute, Predicate canExecute)
             {
                 if (execute == null)
                     throw new ArgumentNullException("execute");
    
                 _execute = execute;
                 _canExecute = canExecute;
             }
    
             #endregion // Constructors
    
             #region ICommand Members
    
             [DebuggerStepThrough]
             public bool CanExecute(object parameter)
             {
                 return _canExecute == null ? true : _canExecute((T)parameter);
             }
    
             public event EventHandler CanExecuteChanged
             {
                 add
                 {
                     if (_canExecute != null)
                         CommandManager.RequerySuggested += value;
                 }
                 remove
                 {
                     if (_canExecute != null)
                         CommandManager.RequerySuggested -= value;
                 }
             }
    
             public void Execute(object parameter)
             {
                 _execute((T)parameter);
             }
    
             #endregion // ICommand Members
    
             #region Fields
    
             readonly Action _execute = null;
             readonly Predicate _canExecute = null;
    
             #endregion // Fields
         }
    
         /// 
         /// A command whose sole purpose is to 
         /// relay its functionality to other
         /// objects by invoking delegates. The
         /// default return value for the CanExecute
         /// method is 'true'.
         /// 
         public class RelayCommand : ICommand
         {
             #region Constructors
    
             /// 
             /// Creates a new command that can always execute.
             /// 
             /// The execution logic.
             public RelayCommand(Action execute)
                 : this(execute, null)
             {
             }
    
             /// 
             /// Creates a new command.
             /// 
             /// The execution logic.
             /// The execution status logic.
             public RelayCommand(Action execute, Func canExecute)
             {
                 if (execute == null)
                     throw new ArgumentNullException("execute");
    
                 _execute = execute;
                 _canExecute = canExecute;
             }
    
             #endregion // Constructors
    
             #region ICommand Members
    
             [DebuggerStepThrough]
             public bool CanExecute(object parameter)
             {
                 return _canExecute == null ? true : _canExecute();
             }
    
             public event EventHandler CanExecuteChanged
             {
                 add
                 {
                     if (_canExecute != null)
                         CommandManager.RequerySuggested += value;
                 }
                 remove
                 {
                     if (_canExecute != null)
                         CommandManager.RequerySuggested -= value;
                 }
             }
    
             public void Execute(object parameter)
             {
                 _execute();
             }
    
             #endregion // ICommand Members
    
             #region Fields
    
             readonly Action _execute;
             readonly Func _canExecute;
    
             #endregion // Fields
         }
    }
    
  • 消息传递Messenger:由于目前我在Revit二开中跨窗口通信较少,所以看这部分代码。用到时在研究。

  • MSDN参考链接:

  • TyperDescripter

  • 弱引用

  • PropertyChangedEventManager

  • CommandManager

你可能感兴趣的:(Revit,高效二次开发)