标题: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相关翻译的文章,请关注……
本文章转载请声明文章出处,以表示对作者的尊重。谢谢。