参考:http://caliburn.codeplex.com/wikipage?title=Command%20Basics&referringTitle=Documentation
command在wpf的viewmodel中使用的非常的广泛,讨论的也非常多.
来看下caliburn对command的支持
caliburn支持三种方式command的注册
- 容器
- 资源
- 绑定
Command解析字符串
parser.RegisterMessageParser("ResourceCommand", new CommandMessageParser(binder, CommandSource.Resource)); parser.RegisterMessageParser("ContainerCommand", new CommandMessageParser(binder, CommandSource.Container)); parser.RegisterMessageParser("BoundCommand", new CommandMessageParser(binder, CommandSource.Bound));
为简化xaml,在Attach中采用了特定解析的字符串,下面可以看到
1.使用容器
首先定义一个对象
注意点:
- 挂上Command标签
- 方法必须为Execute和CanExecute
[Command] public class ShowMessageCommand { //Note: A command must have an entry point. A method named 'Execute' is searched for by default. //Note: Use the CommandAttribute.ExecuteMethod to specify a different method. //Note: The 'Execute' method inherits all the features available to actions. public void Execute(string message) { MessageBox.Show(message); } //NOTE: This is picked up automatically by the ActionFactory based on its naming convention. public bool CanExecute(string message) { return !string.IsNullOrEmpty(message); } }
xaml
<Button Content="Attached Container Command w/ 1 Parameter" cal:Message.Attach="ContainerCommand ShowMessage(message.Text)"/>
注意xaml使用方式,ContainerCommand为特定的解析字符串ShowMessage则代表ShowMessageCommand,以下规则是一样的
2.使用资源
首先然后定义对象,注意Preview标签
public class ShowTitledMessageCommand { //Note: A command must have a method named 'Execute' //Note: The 'Execute' method inherits all the features available to actions. [Preview("CanExecute")] public void Execute(string title, string message) { MessageBox.Show(message, title); } public bool CanExecute(string title, string message) { return !string.IsNullOrEmpty(title) && !string.IsNullOrEmpty(message); } }
<Window.Resources> <!--Note: Adding a command to resources.--> <local:ShowTitledMessageCommand x:Key="ShowTitledMessage" /> </Window.Resources>
<Button Content="Attached Resource Command w/ 2 Parameters" cal:Message.Attach="ResourceCommand ShowTitledMessage(title.Text, message.Text)" />
3.使用绑定
要绑定的前提是需要有源
首先要定义源
<Window.DataContext> <!--Note: Makes the presentation model available for binding through the data context.--> <local:MyModel /> </Window.DataContext>
使用BoundCommand绑定
<TextBox x:Name="message" /> <!--Note: Executes the command located through data binding. The framework infers the trigger type.--> <Button Content="Click Me!" cal:Message.Attach="BoundCommand TheCommand(message.Text)" />
我们通过代码来看下不同的解析过程
protected override void SetCore(CommandMessage message, DependencyObject target, string coreOfMessage) { switch(_commandSource) { case CommandSource.Resource: var frameworkElement = target as FrameworkElement; if(frameworkElement != null) { frameworkElement.Loaded += delegate { message.Command = frameworkElement.GetResource<object>(coreOfMessage); }; } break; case CommandSource.Container: message.Command = ServiceLocator.Current.GetInstance(null, coreOfMessage); break; case CommandSource.Bound: var binding = new Binding(coreOfMessage); BindingOperations.SetBinding(message, CommandMessage.CommandProperty, binding); break; default: throw new NotSupportedException(_commandSource + " is not a supported command source."); } }
实质上是非常简单的,主要手段还是通过给CommandMessage的Command赋值,方式不同而已.以上三种方式一比较,第一种是最简单的,这也是依赖注入带来的好处,不需要事先显示声明对象.效果都是一样的
来看下原始的用法
<Button Content="Triggers: Container Command With 1 Explicit Parameters"> <cal:Message.Triggers> <cal:RoutedMessageTriggerCollection> <cal:EventMessageTrigger EventName="Click"> <cal:EventMessageTrigger.Message> <!--Note ResolveExtension doesn't exist in Silverlight, but you can auto resolve by string key. See SL samples.--> <cal:CommandMessage Command="{cal:Resolve Key=ShowMessage}"> <!--Note: The declaration of parameters is different from Silverlight.--> <cal:Parameter Value="{Binding ElementName=message, Path=Text}"/> </cal:CommandMessage> </cal:EventMessageTrigger.Message> </cal:EventMessageTrigger> </cal:RoutedMessageTriggerCollection> </cal:Message.Triggers> </Button>