折腾MVC的你,用Caliburn折腾过MVVM吗?

引言:什么是Caliburn ?

一个夜晚,一处教堂,人们忏悔结束后抬头看到一把宝剑插在一块石头上。石上字述“英格兰人,凡能从石头上拔出剑者,为王者!”,Caliburn就是英格兰人心中的石中剑,这把剑的主人是亚瑟王,但是在一次格斗中,这把剑被伯林诺王斩断。

Caliburn用于一个MVVM产品的名称,其用意明显,作者是想借助于Caliburn的“锋利”来描述这个产品。

Caliburn是一个功能全面的MVVM产品,全面的同时带来了代码量的庞大,作者在这个基础上做了一个精简版,名为 Caliburn.Micro,简写为CM。

一:Caliburn环境搭建

1,Caliburn.Micro的下载地址:https://caliburnmicro.codeplex.com/releases/view/108277,下载完成后可以看一个名为Caliburn.Micro v1.5.2 Snapshot.zip的压缩包。

随时间推移,版本有可能更新,导致名字的变化,此版本下载于2014-10-28 08:07。

2,解压过后可以看到如下目录,每个目录我做了一个简单的备注,如果做应用型开发,我们只需关注samples就够了。

点开bin目录,我们可以看到Caliburn.Micro可用于silverlight,wpf,wp的开发应用。这篇博客重点以WPF的应用来表述MVVM的用法。

二:WPF下的Caliburn.Micro理论

1:双向绑定

在做WPF下的MVVM编码时,我们先普及一个WPF的常识,在WPF中一般有双向绑定的机制,我们看到很多WPF程序的model,viewmodel都继承自INotifyPropertyChanged接口,其实这是在为双向绑定作铺垫。

PropertyChangedBase 继承自 INotifyPropertyChanged ,当我们向UI传递属性变化并且更新客户端UI时会用到INotifyPropertyChanged。

当一个集合项改变时我们则需要使用ObservableCollection<T>。

一般情况下,MVVM的ViewModel都会继承PropertyChangedBase类,以便实现双向绑定机制。

2:Action的处理

ActionMessage,利用TriggerAction的EventTrigger,可以把UI控件中的事件对应到后台方法,类似于CallMethodAction。Caliburn.Micro对ActionMessage进行了扩展,可以传入多个参数,参数支持绑定等功能。

3:Conventions的约定

Conventions,约定,只要View与ViewModel都遵守约定,就会有意想不到的效果,比如神奇的智能匹配。CM制定了一系列匹配的规则,View和ViewModel之间的匹配,控件名与属性,方法的匹配。

4:Screen

在Caliburn中,Screen用来表示UI部件,并且定义UI部件的生命周期(Activated,DeActivated等)。Conductor用来管理Screen,一个Conductor可以管理一组Screen。

三:Caliburn.Micro的引导模式

1:标准WPF程序的引导

标准的WPF的启动程序都是从设置Application结点的StartupUri属性开始的。如下代码:

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">

2:Caliburn.Micro程序的引导

Caliburn.Micro有自己的引导类,引导类主要通过Configure方法,采用MEF技术组合应用程序部件。

引导类的GetInstance,GetAllInstances,BuildUp,OnStartup方法写法比较固定。除非有特殊的需求,基本不用修改。不过要注意silverlight,wpf,wp写法上略有差异。

比如在实例化CompositionContainer容器时,silverlight用CompositionHost.Initialize方法,WPF用CompositionContainer构造函数。

在用SimpleContainer容器代替CompositionContainer容器时,应在OnStartup方法中加上DisplayRootViewFor<IShell>();这句代码。还有若干的细节问题我们可以在samples例子中慢慢品味。

public class AppBootstrapper : Bootstrapper<IShell>
{
    private CompositionContainer _container;
    //用MEF组合部件
    protected override void Configure()
    {
        _container = new CompositionContainer(
            new AggregateCatalog(
                    AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
                )
            );
        //Silverlight版本
        //C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client\System.ComponentModel.Composition.Initialization.dll
        //container = CompositionHost.Initialize(
        //    new AggregateCatalog(
        //            AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
        //        )
        //    );

        ///如果还有自己的部件都加在这个地方
        CompositionBatch _batch = new CompositionBatch();
        _batch.AddExportedValue<IWindowManager>(new WindowManager());
        _batch.AddExportedValue<IEventAggregator>(new EventAggregator());
        _batch.AddExportedValue(_container);
        _container.Compose(_batch);
    }

    //根据传过来的类型和名称获取实例
    protected override object GetInstance(Type service, string key)
    {
        string _contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
        var _exports = _container.GetExportedValues<object>(_contract);
        if (_exports.Any())
        {
            return _exports.First();
        }
        throw new Exception(string.Format("找不到{0}实例", _contract));
    }

    //获取某一特定类型的所有实例
    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return _container.GetExportedValues<object>(AttributedModelServices.GetContractName(service));
    }

    //将实例传递给 Ioc 容器,使依赖关系注入
    protected override void BuildUp(object instance)
    {
        _container.SatisfyImportsOnce(instance);
    }

    protected override void OnStartup(object sender, StartupEventArgs e)
    {
        base.OnStartup(sender, e);
        //Silverlight
        //Application.Current.RootVisual = new ShellView();
        //SimpleContainer
        //DisplayRootViewFor<IShell>();
    }
}

3:设置引导类的启动

在silverlight中,启动一个引导类

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Caliburn.Micro.Hello"
             x:Class="Caliburn.Micro.Hello.App">
    <Application.Resources>
        <local:HelloBootstrapper x:Key="bootstrapper" />
    </Application.Resources>
</Application>

在wpf中启动一个引导类为

<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local ="clr-namespace:Calib.DWpfApp1"
             x:Class="Calib.DWpfApp1.App">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary>
                    <local:AppBootstrapper x:Key="bootstrapper" />
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

四:代码实践

在xaml编程中,一般都会借助于Blend的两个类库 System.Windows.Interactivity.dll和Microsoft.Expression.Interactions.dll来进行编程。具体引用如下:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
<!--或者-->
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

此处只引用了System.Windows.Interactivity.dll类库。

<Window x:Class="Calib.DWpfApp1.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:cm="http://www.caliburnproject.org"
        Title="MainView" Height="500" Width="500">

a,Caliburn.Micro根据UI元素名称匹配ViewModel的方法(无参数)

<Button x:Name="OpenOneChild1" Content="打开窗口(无参)" Width="240" Height="30"/>

b,Caliburn.Micro使用Message.Attach匹配ViewModel方法(无参数)

<Button Content="打开窗口(无参)" Width="240" Height="30" cm:Message.Attach="OpenOneChild1" />

c,Caliburn.Micro借助于TriggerAction实现ViewModel方法的调用(有参数)

<Button  Content="打开窗口(有参)" Width="240" Height="30">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <cm:ActionMessage MethodName="OpenOneChild2">
                <cm:Parameter Value="hello..."></cm:Parameter>
            </cm:ActionMessage>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

d,Caliburn.Micro使用Message.Attach匹配ViewModel方法(有参数)

<Button Content="打开窗口(有参,简写)" Width="240" Height="30" cm:Message.Attach="[Event Click] = [Action OpenOneChild2(‘woo~‘)]" />

e,Caliburn.Micro使用Message.Attach匹配多个ViewModel方法(有参数)

<Button Content="打开窗口(有参,简写,两个事件)" Width="240" Height="30" cm:Message.Attach="[Event MouseEnter] = [Action Show(‘Enter‘)];[Event MouseLeave] = [Action Show(‘Leave‘)]" />

f,cm:Action.Target 用法

<ListBox Height="100"  Name="listBox1" SelectionMode="Multiple" >
    <ListBoxItem>这是第一项</ListBoxItem>
    <ListBoxItem>这是第二项</ListBoxItem>
    <ListBoxItem>这是第三项</ListBoxItem>
</ListBox>
<Button Content="全选" HorizontalAlignment="Left" Focusable="False"  Name="button1"
        cm:Action.Target="{Binding ElementName=listBox1}"
        cm:Message.Attach="[Event Click] = [Action SelectAll]"/>

ViewModel的源码参考

[Export(typeof(IShell))]
public class MainViewModel : PropertyChangedBase
{
    readonly IWindowManager windowManager;
    public string MainTitle
    {
        get;
        private set;
    }
    [ImportingConstructor]
    public MainViewModel(IWindowManager wmanager)
    {
        MainTitle = "主窗体-MainView";
        windowManager = wmanager;
    }

    public void OpenOneChild1()
    {
        ChildWindowViewModel childViewModel = new ChildWindowViewModel();
        windowManager.ShowDialog(childViewModel);
    }

    public void OpenOneChild2(String para1)
    {
        ChildWindowViewModel childViewModel = new ChildWindowViewModel();
        windowManager.ShowDialog(childViewModel);
    }

    public void Show(String para1)
    {
        System.Windows.MessageBox.Show(para1);
    }
}

 五:总结

近段时间接手惠普给我们公司开发的一个项目,我负责WPF程序部份,以前也断断续续的做过wpf的项目,但是用的是MVVMLight,这个项目用的是Caliburn.Micro。

所以在Caliburn.Micro上下了几天功夫。学习来源于网络,也发表一篇与大家共勉。

帮忙右下角“赞”一下,“赞”的高尿的远!

时间: 2024-11-07 18:08:39

折腾MVC的你,用Caliburn折腾过MVVM吗?的相关文章

折腾开源WRT的AC无线路由之路-1

Tags: tomato, dd-wrt, Netgear, NightHawk, R7000, RT-AC68U, RT-AC66U, N66U, N56U, WRT1900AC, Archer C7, Asus, TP-Link, RT13U, 曾经买的第一个无限路由器是在21世纪初的几年吧,忘了具体年份了,反正是降价处理,于是没管三七二十一的就买了,要说当时热衷于打包日(Boxing Day)的各种淘宝,早起排队冻得贼死的日子都热情高涨地享受着,大打折当然不能错过.可是这个东东太不争气,老

Linux江湖:Just for 折腾

我在博客园开博已经有七年又十个月了.不幸的是,我的博客里一篇东西都没有.我七年又十个月前选择博客园的时候,博客园还不是像现在这样的大杂烩.那时,博客园的内容主要是.net方向的,同时,博客园还有两个分站,一个是www.cppblog.com,一个是www.blogjava.net,分别让用户发布C++和Java方面的文章和随笔.现在,www.cnblogs.com这个主站俨然有一统江湖之势,我在另外两个分站上的博客访客寥寥.So,我又把这个闲置了快八年的博客启用了. 我是非常喜欢博客园的,这么多

笔记本安装centos6.4啥折腾

楼主自去年安装了linux,笔记本就响起来了. 楼主分析原因: 1.第一次安装是完全安装,楼主以为系统安装软件太多,资源不够.没有理会,继续想,继续发热.(这时候楼主还不知道top命令) 2.后来楼主安装以最小桌面安装,以为这下就不会响,不会发热了.结果依旧.找度娘说:显卡问题.还有电源管理问题,风扇问题,硬盘问题. 楼主开始折腾,先说显卡问题: 楼主用的是ATI的显卡,hd5650的,从官网下载安装之后,笔记本分辨率变了,亮度变为最亮.不同调暗.不知道怎么解决,于是卸载.恢复原来. 楼主接着折

被误解的 MVC

MVC模式(Model–view–controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller). MVC模式最早由Trygve Reenskaug在1978年提出,是施乐帕罗奥多研究中心(Xerox PARC)在20世纪80年代为程序语言Smalltalk发明的一种软件架构.MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能.除此之外,此模式通过对复

前端MVC框架对比

首先要特别说明一下,作者认为以下四个功能是十分重要的: UI Bindings(UI绑定):作者想说的不仅仅是模板,而是想谈一种在底层模型出现变化时,视图层能够自动相应地更新的陈述性方法.一旦您用过了支持UI Binding的框架(例如Flex)就很难放手回头了. Composed Views(模块化视图):与所有的软件开发者一样,作者也喜欢编写模块化.可重用的代码.基于这样的原因,当给UI编程的时候,作者喜欢使用视图的方法来创作(个人更偏好在模板层时使用),当然这样也就需要拥有足够丰富的视图组

【JavaScript】对比12 款优秀的JavaScript MVC/MVVC框架 你最喜欢Backbone or Ember

http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/ 目前基本所以后台程序都是面向对象MVC模式开发,作为Web前端开发的人来说,也是很需要的,那么目前有没有可以借鉴的呢?作者(Gordon L.Hempton)一直在寻求哪种MVC框架最为完美,他将目前能获取到的所有框架都粗略地试了试,然后在文章中列出了每一种框架的情况概要,在文末分享了作者经过对比之后最终的推荐产品. 首先要特别说明一下,作者认为

前端mvc与mvvm

框架与库的最大区别就是代码的风格确认,库只是页面级别的选择,而架构则关注于整个程序的设计 MVC 作为软件中的99口诀,软件设计要是没个mvc就好像不是正规军一样,前端也是这样,将html理解为view,js理解为controller,js的通讯(主要指ajax)交互理解为model的获取,那么前端就是一个标准的mvc架构,其写法大致是这样的 html/view: <button class="btn btn-info" id='save'>提交</button>

多款优秀的 JS MVC 框架对比

正如之前说的,产品生产有功能时代转入体验时代,产品为王,体验为王,已经是时代趋势.体验经济的到来,说明前端的技术要求越来越高,完成功能是不行的,还要有优秀的体验.        所以类似原来的jquery时代类似于传统的汇编或者是C时代的编程,这个阶段已经不work了.前端的技术即将迈入模式时代,MVC时代.应此而生,现在有大量的前端MVC框架技术不断出现.下面我们挑选几款代表性的前端框架进行对比,以做参考.1.  Backbone.js Backbone.js是web非常火的框架,众多知名品牌

【转】被误解的MVC和被神化的MVVM

被误解的MVC和被神化的MVVM 作者 唐巧 发布于 2015年11月2日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办 被误解的 MVC MVC 的历史 MVC,全称是 Model View Controller,是模型 (model)-视图 (view)-控制器 (controller) 的缩写.它表示的是一种常见的客户端软件开发框架. MVC 的概念最早出现在二十世纪八十年代的 施乐帕克 实验室中(对,就是那个发明图形用户界面和鼠标的实验室),当时施乐帕