zoukankan      html  css  js  c++  java
  • 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 SDKsSilverlightv4.0LibrariesClientSystem.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上下了几天功夫。学习来源于网络,也发表一篇与大家共勉。

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

     

  • 相关阅读:
    Building a Space Station POJ
    Networking POJ
    POJ 1251 Jungle Roads
    CodeForces
    CodeForces
    kuangbin专题 专题一 简单搜索 POJ 1426 Find The Multiple
    The Preliminary Contest for ICPC Asia Shenyang 2019 F. Honk's pool
    The Preliminary Contest for ICPC Asia Shenyang 2019 H. Texas hold'em Poker
    The Preliminary Contest for ICPC Asia Xuzhou 2019 E. XKC's basketball team
    robotparser (File Formats) – Python 中文开发手册
  • 原文地址:https://www.cnblogs.com/xcj26/p/4054222.html
Copyright © 2011-2022 走看看