Blend Behavior的 使用简介 实现原理以及在MVVM框架的妙用

Behavior的实现原理以及在MVVM框架的妙用

 

摘要 : Behavior 是微软在Blend中新添加的功能,通过在Blend中通过拖拖鼠标很容易就可以通过behavior给元素添加移动 旋转 拉伸等等效果,并且实现行为的代码和UI元素是分离的因此行为是可以复用的大大的提高了编程的灵活性并减少了编写重复枯燥的代码。虽然行为是在Blend中使用的并且使用起来十分简答,但是背后的实现原理以及思想还是值得研究一番。本文将从behavior的基本概念、具体使用方法、实现原理以及在项目中的具体实践对behavior做一个介绍。

大纲:

1 Behavior基本概念

Behavior 行为是微软在Blend中提供的一种新的功能,我觉得其最大的好处我觉得是可以复用,可以将实现的一个功能比如一个动画效果 事件响应方法等附加到某个元素上 那么被附加的元素就具有了相应的功能而不需要重复实现这些功能。比如Blend中自带了一些已经实现的行为只需要拖到需要用到的元素上元素就具有了对应的行为 比如拖动、放大缩小等等; 实现行为的代码和使用行为的元素可以处于不同的程序集中两者是松耦合的。

2 Blend 中的Behavior以及自定义Behavior

在blend中有一些的行为如图1-1所示:

 

使用非常简单只需要将相应的行为拖到需要应用此行为的元素上即可

<i:Interaction.Behaviors>

<el:MouseDragElementBehavior/>

</i:Interaction.Behaviors>

以上代码是将行为拖到某个元素后Blend自动生成的代码,其实就是给元素赋了一个附加属性的值,被附加该行为的元素就可以拖动了。

 

自定义行为:

以上是Blend中以实现的行为,接下来介绍如何自定义行为这里也是自己实现一个支持鼠标拖动的行为。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace BehaviorLibrary
{
    public class DiagInCanvasBehavior:Behavior<UIElement>
    {
        private Canvas canvas;
        private bool isDragging=false;
        private Point mousePoint;

        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.MouseDown += AssociatedObject_MouseDown;
            this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
            this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.MouseDown -= AssociatedObject_MouseDown;
            this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
            this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
        }

        private void AssociatedObject_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (canvas == null)
            {
                canvas = (Canvas)System.Windows.Media.VisualTreeHelper.GetParent(this.AssociatedObject);
            }

            isDragging = true;
            mousePoint = e.GetPosition(this.AssociatedObject);
            AssociatedObject.CaptureMouse();
        }

        private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDragging)
            {
                Point point = e.GetPosition(canvas);
                Canvas.SetTop(AssociatedObject, point.Y - mousePoint.Y);
                Canvas.SetLeft(AssociatedObject, point.X - mousePoint.X);
            }
        }

        private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isDragging)
            {
                AssociatedObject.ReleaseMouseCapture();
                isDragging = false;
            }
        }
    }
}
View Code

 

在上述自定义的拖放行为就是从Behavior类继承 然后重载OnAttached()方法 ,在这个方法中可以给被附加行为的对象的事件添加具体的响应方法(也即各种具体行为的实现方法);

Behavior的主要作用就是可以附加、优点就是已经实现的行为在将来可以复用,非常的灵活简单。

当然在上述实现的拖放操作也是有其局限性的 首先被附加的对象是从UIElement继承的并且能接受上述使用到的几个鼠标事件,在使用过程中发现将其附加在Button TextBox上时调试发现无法响应鼠标事件深层次的原因还请大家帮忙分析分析.。

3 Behavior具体实现原理

讲到Behavior的实现原理不得不提附加属性,附加属性是个神奇的东西,对于一般属性或是依赖属性若某个对象没有改属性或依赖属性那么直接给他赋值肯定报错,而附加属性则不同,只要该对象从DependencyObject继承那么就可以给该对象设置附加属性,并且被附加的对象对该属性一无所知例如Canvas.Top Grid.Row等;(这里只是对于附加属性的做一个简单片面的介绍 具体了解还需参考其他文档);具体到Behavior就是利用了附加属性附加的功能,可以将行为附加到任何依赖对象;

在这里通过Reflector这一.NET的强大反编译工具反编译System.Windows.Interactivity程序集来看看behavior的具体实现,这里介绍Behavior类 以及Interaction

using System;

    using System.Globalization;

    using System.Threading;

    using System.Windows;

    using System.Windows.Media.Animation;

 

    public abstract class Behavior : Animatable, IAttachedObject

    {

        private DependencyObject associatedObject;

        private EventHandler AssociatedObjectChanged;

        private Type associatedType;

 

        internal event EventHandler AssociatedObjectChanged

        {

            add

            {

                EventHandler handler2;

                EventHandler associatedObjectChanged = this.AssociatedObjectChanged;

                do

                {

                    handler2 = associatedObjectChanged;

                    EventHandler handler3 = (EventHandler) Delegate.Combine(handler2, value);

                    associatedObjectChanged = Interlocked.CompareExchange<EventHandler>(ref this.AssociatedObjectChanged, handler3, handler2);

                }

                while (associatedObjectChanged != handler2);

            }

            remove

            {

                EventHandler handler2;

                EventHandler associatedObjectChanged = this.AssociatedObjectChanged;

                do

                {

                    handler2 = associatedObjectChanged;

                    EventHandler handler3 = (EventHandler) Delegate.Remove(handler2, value);

                    associatedObjectChanged = Interlocked.CompareExchange<EventHandler>(ref this.AssociatedObjectChanged, handler3, handler2);

                }

                while (associatedObjectChanged != handler2);

            }

        }

 

        internal Behavior(Type associatedType)

        {

            this.associatedType = associatedType;

        }

 

        public void Attach(DependencyObject dependencyObject)

        {

            if (dependencyObject != this.AssociatedObject)

            {

                if (this.AssociatedObject != null)

                {

                    throw new InvalidOperationException(ExceptionStringTable.CannotHostBehaviorMultipleTimesExceptionMessage);

                }

                if ((dependencyObject != null) && !this.AssociatedType.IsAssignableFrom(dependencyObject.GetType()))

                {

                    throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, ExceptionStringTable.TypeConstraintViolatedExceptionMessage, new object[] { base.GetType().Name, dependencyObject.GetType().Name, this.AssociatedType.Name }));

                }

                base.WritePreamble();

                this.associatedObject = dependencyObject;

                base.WritePostscript();

                this.OnAssociatedObjectChanged();

                this.OnAttached();

            }

        }

 

        protected override Freezable CreateInstanceCore()

        {

            return (Freezable) Activator.CreateInstance(base.GetType());

        }

 

        public void Detach()

        {

            this.OnDetaching();

            base.WritePreamble();

            this.associatedObject = null;

            base.WritePostscript();

            this.OnAssociatedObjectChanged();

        }

 

        private void OnAssociatedObjectChanged()

        {

            if (this.AssociatedObjectChanged != null)

            {

                this.AssociatedObjectChanged(this, new EventArgs());

            }

        }

 

        protected virtual void OnAttached()

        {

        }

 

        protected virtual void OnDetaching()

        {

        }

 

        protected DependencyObject AssociatedObject

        {

            get

            {

                base.ReadPreamble();

                return this.associatedObject;

            }

        }

 

        protected Type AssociatedType

        {

            get

            {

                base.ReadPreamble();

                return this.associatedType;

            }

        }

 

        DependencyObject IAttachedObject.AssociatedObject

        {

            get

            {

                return this.AssociatedObject;

            }

        }

    }

}
View Code

//*******************Interaction类使用行为的类*******************//

namespace System.Windows.Interactivity

{

    using System;

    using System.Runtime.CompilerServices;

    using System.Windows;

 

    public static class Interaction

    {

        private static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached("ShadowBehaviors", typeof(BehaviorCollection), typeof(Interaction), new FrameworkPropertyMetadata(new PropertyChangedCallback(Interaction.OnBehaviorsChanged)));

        private static readonly DependencyProperty TriggersProperty = DependencyProperty.RegisterAttached("ShadowTriggers", typeof(System.Windows.Interactivity.TriggerCollection), typeof(Interaction), new FrameworkPropertyMetadata(new PropertyChangedCallback(Interaction.OnTriggersChanged)));

 

        public static BehaviorCollection GetBehaviors(DependencyObject obj)

        {

            BehaviorCollection behaviors = (BehaviorCollection) obj.GetValue(BehaviorsProperty);

            if (behaviors == null)

            {

                behaviors = new BehaviorCollection();

                obj.SetValue(BehaviorsProperty, behaviors);

            }

            return behaviors;

        }

 

        public static System.Windows.Interactivity.TriggerCollection GetTriggers(DependencyObject obj)

        {

            System.Windows.Interactivity.TriggerCollection triggers = (System.Windows.Interactivity.TriggerCollection) obj.GetValue(TriggersProperty);

            if (triggers == null)

            {

                triggers = new System.Windows.Interactivity.TriggerCollection();

                obj.SetValue(TriggersProperty, triggers);

            }

            return triggers;

        }

 

        internal static bool IsElementLoaded(FrameworkElement element)

        {

            return element.IsLoaded;

        }

 

        private static void OnBehaviorsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)

        {

            BehaviorCollection oldValue = (BehaviorCollection) args.OldValue;

            BehaviorCollection newValue = (BehaviorCollection) args.NewValue;

            if (oldValue != newValue)

            {

                if ((oldValue != null) && (oldValue.AssociatedObject != null))

                {

                    oldValue.Detach();

                }

                if ((newValue != null) && (obj != null))

                {

                    if (newValue.AssociatedObject != null)

                    {

                        throw new InvalidOperationException(ExceptionStringTable.CannotHostBehaviorCollectionMultipleTimesExceptionMessage);

                    }

                    newValue.Attach(obj);

                }

            }

        }

 

        private static void OnTriggersChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)

        {

            System.Windows.Interactivity.TriggerCollection oldValue = args.OldValue as System.Windows.Interactivity.TriggerCollection;

            System.Windows.Interactivity.TriggerCollection newValue = args.NewValue as System.Windows.Interactivity.TriggerCollection;

            if (oldValue != newValue)

            {

                if ((oldValue != null) && (oldValue.AssociatedObject != null))

                {

                    oldValue.Detach();

                }

                if ((newValue != null) && (obj != null))

                {

                    if (newValue.AssociatedObject != null)

                    {

                        throw new InvalidOperationException(ExceptionStringTable.CannotHostTriggerCollectionMultipleTimesExceptionMessage);

                    }

                    newValue.Attach(obj);

                }

            }

        }

 

        internal static bool ShouldRunInDesignMode

        {

            [CompilerGenerated]

            get

            {

                return <ShouldRunInDesignMode>k__BackingField;

            }

            [CompilerGenerated]

            set

            {

                <ShouldRunInDesignMode>k__BackingField = value;

            }

        }

    }

}
View Code

 

Interaction类中我们可以看到  private static readonly DependencyProperty BehaviorsProperty = DependencyProperty.RegisterAttached("ShadowBehaviors", typeof(BehaviorCollection), typeof(Interaction), new FrameworkPropertyMetadata(new PropertyChangedCallback(Interaction.OnBehaviorsChanged))); BehaviorsProperty这个附加属性 回顾在Blend中自动生成的代码如下

<i:Interaction.Behaviors>

<el:MouseDragElementBehavior/>

</i:Interaction.Behaviors>

就是给附加行为的元素设置了Interaction.Behaviors这个附加属性,这里注册附加属性时非常重要一点就是PropertyChangedCallback这个回调委托通过这个函数可以得到此附加属性被附加的对象的一个引用;

在讲这个回调函数之前先来看看Behavior类的功能 Behavior实现了IAttachedObject   接口 该接口定义如下;

  public interface IAttachedObject   

{

         DependencyObject AssociatedObject { get; }     

         void Attach(DependencyObject dependencyObject);   

         void Detach();

    }

实现这个接口的类的实例可以被附加到另一个对象,通常我们在自定义行为的时候不是直接继承自IAttachedObject接口,而是继承自从 IAttachedObject继承的一些类,这些类都有可重载的OnAttached(),OnDetached()方法,比如 在上面所介绍的自定义行为就是从Behavior类继承然后重载上述方法; 再回到Interaction类BehaviorsProperty 的类型是 BehaviorCollection 其实是Behavior类的集合形式这样就可以给一个元素同时附加多个行为,因此了解了Behavior类的代码就对BehaviorCollection也能触类旁通。在了解了Behavior类以及IAttachedObject接口后接着讲PropertyChangedCallback回调内托在该委托调用的方法OnBehaviorsChanged 中就是将行为附加到被附加属性附加的对象   newValue.Attach(obj);(回调函数中的关键代码)

通过上面的源码分析我们可以发现行为的实现机制还是很简单的,利用了附加属性以及IAttachedObject接口 给附加的对象添加一些特定的代码也即某些行为比如拖放操作就是通过响应附加对象的几个鼠标事件来实现了一个简单的拖放功能;

4Blend中的Behavior的扩展应用

为了满足MVVM模式的要求 需要将View层后台无代码,用户在View上的操作通过命令在ViewModel层中进行响应,然而除了Button ContextMenu等几个有限的控件内置实现了事件触发命令的功能 大部分的控件的相关事件并无法和ViewModel建立关联,为了解决上述问题在我们开发项目中用到的MVVM框架中借鉴Blend中Behavior行为的实现机制通过附加的思想可以将View层控件触发的事件 与命令建立联系 从而在ViewModel层执行。

下面给出具体实现代码:

using System;

using System.Collections.Specialized;

using System.Linq;

using System.Reflection;

using System.Windows;

using System.Windows.Input;

 

namespace Wpf.MVVM.Foundation.Behaviors

{

    ///<summary>

    ///功能描述:1.执行事件与命令的链接与移除链接功能

    ///          2.继承至Freezable,主要利用其与WPF的传递DataContext功能

    ///创建人:*** 

    ///编写日期:2013-08-01

    ///</summary>

    public class CommandEvent : Freezable

    {

        #region 依赖属性定义

        /// <summary>

        /// Command依赖属性定义

        /// </summary>

        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandEvent), new UIPropertyMetadata(null));

 

        /// <summary>

        /// CommandParameter依赖属性定义,Command的参数

        /// </summary>

        public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandEvent), new UIPropertyMetadata(null));

 

        /// <summary>

        /// 事件依赖属性定义

        /// </summary>

        public static readonly DependencyProperty EventProperty = DependencyProperty.Register("Event", typeof(String), typeof(CommandEvent), new UIPropertyMetadata(string.Empty));

        #endregion //依赖属性定义

 

        #region 属性/变量定义

        /// <summary>

        /// 获取或设置事件Event依赖属性

        /// </summary>

        public string Event

        {

            get { return (string)GetValue(EventProperty); }

            set { SetValue(EventProperty, value); }

        }

 

        /// <summary>

        /// 获取或设置命令Command依赖属性

        /// </summary>

        public ICommand Command

        {

            get { return (ICommand)GetValue(CommandProperty); }

            set { SetValue(CommandProperty, value); }

        }

 

        /// <summary>

        ///获取或设置命令参数CommandParameter依赖属性

        /// </summary>

        public object CommandParameter

        {

            get { return GetValue(CommandParameterProperty); }

            set { SetValue(CommandParameterProperty, value); }

        }

        #endregion 属性/变量定义

 

        #region 私有函数

        /// <summary>

        /// 将事件和命令进行链接

        /// </summary>

        /// <param name="target">所附加的窗体对象</param>

        internal void Subscribe(object target)

        {

            if (target == null)//若附加对象为null,直接退出

                return;

 

            string eventName = Event;

            EventInfo ei = target.GetType().GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance);//在附加窗体对象中查找事件类型

            if (ei != null)

            {

                ei.RemoveEventHandler(target, GetEventMethod(ei));//处于安全目的,首先移除事件处理委托

                ei.AddEventHandler(target, GetEventMethod(ei));//添加事件处理委托

                return;

            }

 

            //移除事件名称字符串中可能存在的命令空间字符串

            int dotPos = eventName.IndexOf(':');

            if (dotPos > 0)

                eventName = eventName.Substring(dotPos + 1);

 

 

            dotPos = eventName.IndexOf('.');   // 查找依赖对象的附加路由事件

            if (dotPos > 0 && eventName.Length > dotPos)

            {

 

                var attachedEvent = EventManager.GetRoutedEvents().Where(evt => evt.ToString() == eventName).SingleOrDefault();//在事件管理中,查找对应的路由事件

                if (attachedEvent == null)//未查找到,直接返回

                    return;

 

                FrameworkElement fe = target as FrameworkElement;

                if (fe == null)

                    return;

 

                fe.RemoveHandler(attachedEvent, GetRoutedEventMethod());//处于安全目的,首先移除路由事件处理委托

                fe.AddHandler(attachedEvent, GetRoutedEventMethod());//添加路由事件处理委托

            }

        }

 

        /// <summary>

        /// 解除事件和命令的链接

        /// </summary>

        /// <param name="target">所附加的窗体对象</param>

        internal void Unsubscribe(object target)

        {

            if (target == null)//若附加对象为null,直接退出

                return;

 

            EventInfo ei = target.GetType().GetEvent(Event, BindingFlags.Public | BindingFlags.Instance);

            if (ei != null)//常规事件,直接移除事件委托

            {

                ei.RemoveEventHandler(target, GetEventMethod(ei));

                return;

            }

 

            string eventName = Event;

 

            //移除事件名称字符串中可能存在的命令空间字符串

            int dotPos = eventName.IndexOf(':');

            if (dotPos > 0)

                eventName = eventName.Substring(dotPos + 1);

 

            dotPos = eventName.IndexOf('.'); // 查找依赖对象的附加路由事件

            if (dotPos > 0 && eventName.Length > dotPos)

            {

                //在事件管理中,查找对应的路由事件

                var attachedEvent = EventManager.GetRoutedEvents().Where(evt => evt.Name == eventName).SingleOrDefault();

                if (attachedEvent != null)

                {

                    FrameworkElement fe = target as FrameworkElement;

                    if (fe != null)//移除路由事件处理委托

                        fe.RemoveHandler(attachedEvent, GetRoutedEventMethod());

                }

            }

        }

 

        /// <summary>

        ///  获取事件的执行委托

        /// </summary>

        /// <param name="ei">事件信息</param>

        /// <returns>返回事件的执行委托,失败,返回null</returns>

        private Delegate GetEventMethod(EventInfo ei)

        {

            if (ei == null || ei.EventHandlerType == null)

                return null;

 

            return Delegate.CreateDelegate(ei.EventHandlerType, this, GetType().GetMethod("OnEventRaised", BindingFlags.NonPublic | BindingFlags.Instance));

        }

 

        /// <summary>

        /// 获取路由事件的执行委托

        /// </summary>

        /// <returns>返回路由事件的执行委托,失败,返回null</returns>

        private Delegate GetRoutedEventMethod()

        {

            return Delegate.CreateDelegate(typeof(RoutedEventHandler), this, GetType().GetMethod("OnEventRaised", BindingFlags.NonPublic | BindingFlags.Instance));

        }

 

        /// <summary>

        /// 该方法被事件调用,其调用命令处理函数

        /// </summary>

        /// <param name="sender">事件发送者</param>

        /// <param name="e">参数</param>

        private void OnEventRaised(object sender, EventArgs e)

        {

            if (Command == null)

               return;

            ICommand c = Command;

            if (Command.CanExecute(CommandParameter))

                Command.Execute(CommandParameter);

        }

        #endregion //私有函数

 

        #region Freezable 抽象成员实现

        /// <summary>

        /// 未实现,返回null

        /// </summary>

        /// <returns>返回null</returns>

        protected override Freezable CreateInstanceCore()

        {

            return null;

        }

        #endregion Freezable 抽象成员实现

    }

 

 

    ///<summary>

    ///功能描述:1.事件与命令映射的集合

    ///          2.继承至FreezableCollection<T>,主要为在WFP Visual Tree 上传递DataContext对象

    ///创建人:*** 

    ///编写日期:2013-08-01

    ///</summary>

    public class CommandEventCollection : FreezableCollection<CommandEvent>

    {

        #region 属性/变量

        private object _target;//附加对象

        #endregion //属性/变量

 

        #region 构造函数

        /// <summary>

        /// 构造函数

        /// </summary>

        public CommandEventCollection()

        {

            ((INotifyCollectionChanged)this).CollectionChanged += OnCollectionChanged;//添加集合变更事件处理函数

        }

        #endregion //构造函数

 

        #region 私有函数

        /// <summary>

        /// 集合中的命令和事件进行链接

        /// </summary>

        /// <param name="target">附加对象</param>

        internal void Subscribe(object target)

        {

            _target = target;//初始化附加对象

 

            foreach (var item in this)

                item.Subscribe(target);

        }

 

        /// <summary>

        /// 集合中的命令和事件解除链接

        /// </summary>

        /// <param name="target">附加对象</param>

        internal void Unsubscribe(object target)

        {

            foreach (var item in this)

                item.Unsubscribe(target);

 

            _target = null;

        }

 

        /// <summary>

        /// 事件与命令的集合变更函数

        /// </summary>

        /// <param name="sender">事件触发者</param>

        /// <param name="e">参数</param>

        private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)

        {

            switch (e.Action)//集合变更类型

            {

                case NotifyCollectionChangedAction.Add://添加新元素

                    foreach (var item in e.NewItems)

                        OnItemAdded((CommandEvent)item);

                    break;

 

                case NotifyCollectionChangedAction.Remove://移除元素

                    foreach (var item in e.OldItems)

                        OnItemRemoved((CommandEvent)item);

                    break;

 

                case NotifyCollectionChangedAction.Replace://更新元素

                    foreach (var item in e.OldItems)

                        OnItemRemoved((CommandEvent)item);

 

                    foreach (var item in e.NewItems)

                        OnItemAdded((CommandEvent)item);

                    break;

 

                case NotifyCollectionChangedAction.Move:

                    break;

 

                case NotifyCollectionChangedAction.Reset://集合重置

                    foreach (var item in this)

                        OnItemRemoved(item);

 

                    foreach (var item in this)

                        OnItemAdded(item);

                    break;

 

                default:

                    return;

            }

        }

 

        /// <summary>

        /// 添加新元素

        /// </summary>

        /// <param name="item">新元素</param>

        private void OnItemAdded(CommandEvent item)

        {

            if (item != null && _target != null)

            {

                item.Subscribe(_target);

            }

        }

 

        /// <summary>

        /// 移除元素

        /// </summary>

        /// <param name="item">元素</param>

        private void OnItemRemoved(CommandEvent item)

        {

            if (item != null && _target != null)

            {

                item.Unsubscribe(_target);

            }

        }

        #endregion //私有函数

    }

 

    ///<summary>

    ///功能描述:1.管理事件与命令链接集合

    ///          2.继承至FreezableCollection<T>,主要为在WFP Visual Tree 上传递DataContext对象

    ///          3.注意,若为生命周期事件(加载、激活、关闭、已关闭等),请使用生命周期事件行为代替

    ///创建人:*** 

    ///编写日期:2013-08-01

    ///</summary>

    /// <example>

    /// <![CDATA[

    /// 

    /// <Behaviors:EventCommander.Mappings>

    ///    <Behaviors:CommandEvent Command="{Binding MouseEnterCommand}" Event="MouseEnter" />

    ///    <Behaviors:CommandEvent Command="{Binding MouseLeaveCommand}" Event="MouseLeave" />

    /// </Behaviors:EventCommander.Mappings>

    /// 

    /// ]]>

    /// </example>

    public static class EventCommander

    {

        #region 依赖属性定义

        /// <summary>

        /// 事件与命令映射集合附加依赖属性定义

        /// </summary>

        internal static readonly DependencyProperty MappingsProperty = DependencyProperty.RegisterAttached(

                           "InternalMappings",

                            typeof(CommandEventCollection),

                            typeof(EventCommander),

                            new UIPropertyMetadata(null, OnMappingsChanged)

                            );

 

        /// <summary>

        /// Mappings附加依赖属性读取方法

        /// </summary>

        /// <param name="obj">附加对象</param>

        /// <returns>返回附加依赖属性值</returns>

        public static CommandEventCollection GetMappings(DependencyObject obj)

        {

            return InternalGetMappingCollection(obj);

        }

 

        /// <summary>

        /// Mappings附加依赖属性设置方法

        /// </summary>

        /// <param name="obj">附加对象</param>

        /// <param name="value">设置值</param>

        public static void SetMappings(DependencyObject obj, CommandEventCollection value)

        {

            obj.SetValue(MappingsProperty, value);

        }

        #endregion //依赖属性定义

 

        #region 私有函数

        /// <summary>

        /// 获取Mapping依赖属性值,若为null,则初始化为空集合

        /// </summary>

        /// <param name="obj">附加对象</param>

        /// <returns>返回Mapping依赖属性值</returns>

        internal static CommandEventCollection InternalGetMappingCollection(DependencyObject obj)

        {

            var map = obj.GetValue(MappingsProperty) as CommandEventCollection;

            if (map == null)//属性值为null,初始化新集合

            {

                map = new CommandEventCollection();

                SetMappings(obj, map);

            }

 

            return map;

        }

 

        /// <summary>

        /// Mapping附加依赖属性值变更处理函数

        /// </summary>

        /// <param name="target">附加对象</param>

        /// <param name="e">信息参数</param>

        private static void OnMappingsChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)

        {

            if (e.OldValue != null)

            {

                CommandEventCollection cec = e.OldValue as CommandEventCollection;

                if (cec != null)//解除命令与事件链接

                    cec.Unsubscribe(target);

            }

 

            if (e.NewValue != null)

            {

                CommandEventCollection cec = e.NewValue as CommandEventCollection;

                if (cec != null)//进行命令与事件链接

                    cec.Subscribe(target);

            }

        }

        #endregion //私有函数

    }

}
View Code

 

上述代码实现思想和Blend中的Behavior相似,使用方法如下所示

 <Behaviors:EventCommander.Mappings>

 <Behaviors:CommandEvent Command="{Binding MouseEnterCommand}" Event="MouseEnter" /> 

<Behaviors:CommandEvent Command="{Binding MouseLeaveCommand}" Event="MouseLeave" />   </Behaviors:EventCommander.Mappings>

上述代码完成的功能就是将UI的MouseEnter MouseLeave事件分别绑定到ViewModel层的MouseEnterCommand MouseLeaveCommand命令;这样就可以很方便的把View层的UI事件响应代码转移到ViewModel层。

 

上述实现的思路就是给UI元素赋MappingsProperty附加属性的值 在注册的回调函数中获取被附加该依赖属性的UI元素对象,然后通过反射查找到对应名称的事件,并给对应事件添加响应函数然后再响应函数中触发绑定的命令;从而实现了前台UI事件触发ViewModel层的命令的效果;

大体思路如上所示可以结合Blend Behavior的实现代码 对比了解。另外希望各位大神提出宝贵的意见,包括上述实现的不足的地方 ,代码中问题或是有更好地实现方法 ,衷心希望相互交流,共同学习,共同进步;

 

posted @ 2013-11-07 21:39  心渴望  阅读(2705)  评论(1编辑  收藏  举报