代码改变世界

Caliburn笔记-基本Command(wpf框架)

2009-12-29 10:13  Clingingboy  阅读(1451)  评论(1编辑  收藏  举报

参考: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.使用容器

首先定义一个对象

注意点:

  1. 挂上Command标签
  2. 方法必须为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>


xaml引用

<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>