MVVM设计模式之旅 – 通用的命令附加行为

标题:Adventures in MVVM – Generalized Command Behavior Attachments

   网上有很多关于WPF和Silverlight技术描述附加行为的例子。在WVVM模型中这些例子对命令绑定结合的非常好。不过有个问题是,对每一个行为,都会有许伴随代码,因为依赖属性必须是静态的,他们不能被抽象成普通的类。

   如果你想附加为一个Control控件添加一个MouseEnterBehavior的行为,你需要创建两到三个依赖属性在MouseEnter这个类中。他们分别是MouseEnter.Command,MouseEnter.MouseEnterBehavior 和可供选择的MouseEnter.CommandParameter.

 public class MouseEnter 
    {
        private static readonly DependencyProperty BehaviorProperty =
            DependencyProperty.RegisterAttached(
                "MouseEnterBehavior",
                typeof(MouseEnterBehavior),
                typeof(Control),
                null);

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(MouseEnter),
                new PropertyMetadata(OnSetCommand));

        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.RegisterAttached(
                "CommandParameter",
                typeof(object),
                typeof(MouseEnter),
                new PropertyMetadata(OnSetParameter))
//接下来就是处理一些依赖属性的更改

        private static void OnSetCommand(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var target = dependencyObject as Control;
            if (target == null)
                return;

            GetOrCreateBehavior(target).Command = args.NewValue as ICommand;
        }

        private static void OnSetParameter(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
        {
            var target = dependencyObject as Control;
            if (target != null)
            {
                GetOrCreateBehavior(target).CommandParameter = args.NewValue;
            }
        }

        protected static MouseEnterBehavior GetOrCreateBehavior(Control control)
        {
            var behavior = control.GetValue(BehaviorProperty) as MouseEnterBehavior;
            if (behavior == null)
            {
                behavior = new MouseEnterBehavior(control);
                control.SetValue(BehaviorProperty, behavior);
            }

            return behavior;
        }

     虽然依赖属性是静态的,但是Silverlight 仍然需要你添加静态的Get和Set方法:

        public static void SetCommand(Control control, ICommand command) { control.SetValue(CommandProperty, command); }
        public static ICommand GetCommand(Control control) { return control.GetValue(CommandProperty) as ICommand; }
        public static void SetCommandParameter(Control control, object parameter) { control.SetValue(CommandParameterProperty, parameter); }
        public static object GetCommandParameter(Control buttonBase) { return buttonBase.GetValue(CommandParameterProperty); }

    经典的案例就是复制粘贴,完成其他相同的功能。为题就是你需要更改三处不同的类型和许多字符串。
如果你调用的不得当,那么将不会程序讲不会起作用。能编译,但是就是不能运行,或者程序停在在xaml中出现转化错误。

每当我必须运用复制粘贴达到重用时,我便很沮丧,畏缩。在这种情况下,那些是绝对必须要的,如this。
我相信降低风险的方法就是粘贴之后疯狂的而复杂的更改。这就是之所以提出用AttachmentBasse这个类来达到通用的代码的原因。

上述代码就可以缩减为:

 public class MouseEnter : Attachment<Control, MouseEnterBehavior, MouseEnter>
    {
        private static readonly DependencyProperty BehaviorProperty = Behavior();
        public static readonly DependencyProperty CommandProperty = Command(BehaviorProperty);
        public static readonly DependencyProperty CommandParameterProperty = Parameter(BehaviorProperty);

        public static void SetCommand(Control control, ICommand command) { control.SetValue(CommandProperty, command); }
        public static ICommand GetCommand(Control control) { return control.GetValue(CommandProperty) as ICommand; }
        public static void SetCommandParameter(Control control, object parameter) { control.SetValue(CommandParameterProperty, parameter); }
        public static object GetCommandParameter(Control buttonBase) { return buttonBase.GetValue(CommandParameterProperty); }
    }

这里你如果需要复制,你仅仅需要修改第一行就行了。

1.类名是什么?MouseEnter,修改两处

2.行为应该附加到那中类型的控件上?Control

3.你想附加那种类型的行为?MouseEnterBehavoir

 处理减少配置复杂程度外,实际代码有原来的58行,缩短到11行代码,我认为这是一个伟大的胜利。

      这这块代码中,我用到了来自prism框架中的CommandBehaviorBase类,他是通用约束中的一部分。如果你想对你的Behaviors用一些其他东西,替代他,按照你想的。我确信你自己的关于命令行为的基类将是非常的简洁。

下面就是Attachment的基类:

 

 public class Attachment<TargetT, BehaviorT, AttachmentT>
        where TargetT : Control
        where BehaviorT : CommandBehaviorBase<TargetT>
    {
        public static DependencyProperty Behavior()
        {
            return DependencyProperty.RegisterAttached(
                typeof(BehaviorT).Name,
                typeof(BehaviorT),
                typeof(TargetT),
                null);
        }

        public static DependencyProperty Command(DependencyProperty behaviorProperty)
        {
            return DependencyProperty.RegisterAttached(
                "Command",
                typeof (ICommand),
                typeof(AttachmentT),
                new PropertyMetadata((target, args) => OnSetCommandCallback(target, args, behaviorProperty)));
        }

        public static DependencyProperty Parameter(DependencyProperty behaviorProperty)
        {
            return DependencyProperty.RegisterAttached(
                "CommandParameter",
                typeof (object),
                typeof (AttachmentT),
                new PropertyMetadata((target, args) => OnSetParameterCallback(target, args, behaviorProperty)));
        }

        protected static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e, DependencyProperty behaviorProperty)
        {
            var target = dependencyObject as TargetT;
            if (target == null)
                return;

            GetOrCreateBehavior(target, behaviorProperty).Command = e.NewValue as ICommand;
        }

        protected static void OnSetParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e, DependencyProperty behaviorProperty)
        {
            var target = dependencyObject as TargetT;
            if (target != null)
            {
                GetOrCreateBehavior(target, behaviorProperty).CommandParameter = e.NewValue;
            }
        }

        protected static BehaviorT GetOrCreateBehavior(Control control, DependencyProperty behaviorProperty)
        {
            var behavior = control.GetValue(behaviorProperty) as BehaviorT;
            if (behavior == null)
            {
                behavior = Activator.CreateInstance(typeof(BehaviorT), control) as BehaviorT;
                control.SetValue(behaviorProperty, behavior);
            }

            return behavior;
        }
    }

最后,为了完成例子,这里给出MouseEnterBehavoior 的示例:

 public class MouseEnterBehavior : CommandBehaviorBase<Control>
    {
        public MouseEnterBehavior(Control selectableObject)
            : base(selectableObject)
        {
            selectableObject.MouseEnter += (sender, args) => ExecuteCommand();
        }
    }


  在Xaml中应用该行为,如下:

<Button Behaviors:MouseEnter.Command="{Binding MouseEnter}" Behaviors:MouseEnter.CommandParameter="Optional Paremeter"/> 


                 *********************翻译文章结束*********************

第一次翻译,不足之处还请大家多多包涵。之后继续退出WPF相关翻译的文章,请关注……

原文地址:http://geekswithblogs.net/HouseOfBilz/archive/2009/08/21/adventures-in-mvvm-ndash-generalized-command-behavior-attachments.aspx

 本文章转载请声明文章出处,以表示对作者的尊重。谢谢。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值