微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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),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,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),args) => OnSetParameterCallback(target,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,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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐