標題: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相關翻譯的文章,請關注……
本文章轉載請聲明文章出處,以表示對作者的尊重。謝謝。