AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(一)
随着IOS7由之前UI的拟物化设计变为如今的扁平化设计,也许扁平化的时代要来了,当然我们是不是该吐槽一下,苹果什么时候也开始跟风了,自GOOGLE和微软界面扁平化过后,苹果也加入了这一队伍。
AvalonDock
AvalonDock 是一个.NET库,用于在停靠模式布局(docking)中排列一系列WPF/WinForm控件。最新发布的版本原生支持MVVM框架、Aero Snap特效并具有更好的性能。
AvalonDock 2.0版本已经发布了,新版本是用MVVM框架重新编写,似乎也用了Command(命令)模式。2.0版的文档尚未发布,但你可以参考Avalon.TestApp 或者2.0版源码中的Avalon.MVVMTestApp文件夹来查看新的API。
这个库使用很简单——只需要用AvalonDock提供的控件包含你自己的控件,页面布局就立即变成可停靠的(dockable)。可以参考 入门 页面获取样例代码,了解不同控件的特性。当然你也可以在自己的C#代码中实例化或操作这些控件。2.0版本中,控件功能与以前一致,但控件名称已经改变,因此建议参考前述样例代码直至参考文档更新为止。
大名鼎鼎SharpEevelop也应用了AvalonDock,由于SharpEevelop的框架过于庞大,并且SharpEevelop里的AvalonDock 1.3的版本,并不支持MVVM的模式,所以就兴起了自己做一个插件式系统,当然也跟一下扁平化的风,目前框架已经做好并应用到个人项目中,本着开源的思想我会把框架搭建的过程,以及遇到的种种问题分享出来。
Caliburn.Micro
Caliburn是Rob Eisenberg在2009年提出的一个开源框架,可以应用于WPF,Silverlight,WP7等,框架基于MVVM模式,像它的名字一样,是企业级应用的一把利器。
基于WPF的框架有很多,Prism,WAF等,每个框架都有自己侧重点,像Prism侧重于模块间的组合,WAF侧重于分层设计。通观CM的设计,它的一些想法如下: 1.ActionMessage,结合了Blend中的TriggerAction,可以把UI控件中的事件绑定到后台方法,类似于CallMethodAction。CM对ActionMessage进行了很多扩展,包括可以传入多个参数,参数支持绑定,可以通过CanExecute作执行前判断并设置控件的Enable等。
2.Conventions,协定,这个词听上去有点虚,其实就是智能匹配的意思。CM制定了一系列匹配的规则,比如说View和ViewModel之间的匹配,绑定时传入控件名可以找到控件,传入方法名可以绑定到方法等等。
3.Screen和Conductor,作为一个Presentation的框架,各个UI部件(Widget或者叫Pad)的管理是必不可少的。Screen就是用来表示UI部件的,它定义了一些列UI部件的生命期事件,比如Activated,DeActivated等。Conductor是用来管理Screen的,类似于传统的Controller,不同的Screen可以用一个Conductor来管理,Conductor也使用了策略模式允许更改对Screen的处理。
4.Coroutines,协同程序,定义了一组程序的执行,简化了异步编程。比如说在网络中下载图片并显示,通常来说需要显示BusyIndicator,后台线程去网络读取图片,读取成功后Invoke到UI线程,取消BusyIndicator,显示图片。CM提供了一个IResult接口,大大的简化了异步编程,结合ActionMessage,为AOP的扩展提供了可能。
5.配置性和扩展性,CM移除掉了原Caliburn的一些IOC实现,作为一个通用框架,最常用办法就是使用工厂模式结合配置文件提供可配置性,使用IOC来解耦组件间的依赖。CM默认是使用MEF来做IOC扩展的,你可以自定义Bootstrapper来使用你喜欢的IOC容器,如Unity等。
6.设计时支持(Design-time support),CM中的ActionMessage是继承自Blend中的TriggerAction的,也就是说可以在Blend编辑ActionMessage,大大方便了使用。 (这段摘抄了周永恒大大的部分对CM框架的解析,大家想详细了解的话可以去他的博客去学习,我就不仔细说明了,以后我会用到的地方做说明)
MahApps.Metro
这是一个Metro样式的开源项目,应用该项目可以使你的软件具有metro的风格,具体就不多说了。
这是测试项目第一阶段的运行结果
言归正传,我们从零开始创建项目,下面是整个测试项目的结构:
MefBootstrapper
这是启动加载类,一般我们WPF程序是从APP.XAML里StartupUri=“****WINDOWS.XAML”来启动主窗体,但现在由MefBootstrapper担当了启动窗体的职责:
public class MefBootstrapper : Bootstrapper<IShell>
{
private CompositionContainer container; protected override void Configure()
{
/*CompositionContainer 对象在应用程序中有两种的主要用途。首先,它跟踪哪些部分可用于组合、它们的依赖项,并且充当任何指定组合的上下文。其次,它提供了应用程序可以启动组合的方法、获取组合部件的实例,或填充可组合部件的依存关系。
部件可直接用于容器,或通过 Catalog 属性来用于容器。在此 ComposablePartCatalog 中可发现的所有部件都可以供容器来满足导入,还包括直接添加的任何部件。*/
container = new CompositionContainer(
new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)))
); var batch = new CompositionBatch();
var dockScreenManager = new DockScreenManager();
batch.AddExportedValue<IWindowManager>(new WindowManager());//將指定的导出加入至 CompositionBatch 物件
batch.AddExportedValue<IDockScreenManager>(dockScreenManager);
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container); container.Compose(batch);//在容器上执行组合,包括指定的 CompositionBatch 中的更改
} protected override object GetInstance(Type serviceType, string key)
{
var contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;//获取指定类型的规范协定名称
var exports = container.GetExportedValues<object>(contract);//返回具有从指定的类型参数派生的协定名称的已导出对象。如果不是正好有一个匹配的已导出对象,则将引发异常。 if (exports.Any())
return exports.First(); throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
} protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
} protected override void BuildUp(object instance)
{
container.SatisfyImportsOnce(instance);//满足指定的 ComposablePart 对象的导入,而无需注册该对象以进行重新组合。
}
}
由上可知, MefBootstrapper继承与CM框架提供Bootstrapper<TRootModel>,当Bootstrapper加载时,CM框架便会从MEF容器里寻找出TRootModel类型的实例,并且show出来,也就是我们的主窗体,之后我会把项目源码放出来,大家可以自己跟踪OnStartup事件。
我们来看看APP.XMAL
<Application x:Class="DemoApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DemoApplication"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:MefBootstrapper x:Key="bootstrapper" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
IShell
一个简单的接口,为了方便MEF导出部件
public interface IShell
{ }
ShellView.xaml
<MetrolControls:MetroWindow x:Class="DemoApplication.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:MetrolControls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="ShellView" Height="" Width="">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl x:Name="DockContent" Margin="0,2,0,0" Grid.Row=""/>
</Grid>
</MetrolControls:MetroWindow>
可以看到,这时我们引用了MahApps.Metro,MahApps.Metro自定义了一个WINDOWS,在我看来比传统的和谐那么一点,MahApps.Metro里还有10多种自定义控件,有兴趣的可以自己去研究
ShellViewModel
[Export(typeof(IShell))]
class ShellViewModel:IShell
{
[Import]
public IScreen DockContent { get; set; }
}
一个ShellView.xaml对应一个ShellViewModel,当ShellViewModel标记为Export时,Bootstrapper会把当前程序集所有标记为Export的类导入CM框架的IOC容器里,ShellViewModel相当于ShellView的Datacontext,一个View的加载过程为,由Model找到(CM框架定义了各种查找规则)View,并把Model绑定到View的Datacontext,以后我们UI的逻辑代码就可以写在Model里面,并与UI完全分开,这就是我们所说的MVVM模式。上面也有一个典型的View绑定Model里的属性,细心的可以看到:
[Import]
public IScreen DockContent { get; set; }
该属性的名称和ShellView.xaml里的<ContentControl x:Name="DockContent" Margin="0,2,0,0" Grid.Row="0"/> 的命名完全一样,奇怪的是我们并没有写任何绑定,但DockContent是怎么绑定到View里面的呢,其实绑定的过程已经由CM框架帮我们做了,CM框架会帮助我们把Model里和控件名称一样的属性绑定在一起,这就然我们省了一些事,这只是CM框架的一些小特性。
好了,主窗体的说完了,下面我们来看看怎么把AvalonDock融合进去,上面我们说过了,一个Model对应一个View,所以我们要显示一个UserControl时得生成一对Model-View,
DockView.xaml
<UserControl x:Class="DemoApplication.Views.DockView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:avalonDock="http://avalondock.codeplex.com"
d:DesignHeight="" d:DesignWidth="">
<UserControl.Resources>
<avalonDock:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</UserControl.Resources>
<Grid>
<Grid x:Name="layoutRoot">
<avalonDock:DockingManager Grid.Row="" x:Name="dockManager" AllowMixedOrientation="True" >
<avalonDock:DockingManager.Theme>
<avalonDock:MetroTheme/>
</avalonDock:DockingManager.Theme>
<avalonDock:DockingManager.LayoutItemTemplate>
<DataTemplate>
<ContentControl IsTabStop="False" />
</DataTemplate>
</avalonDock:DockingManager.LayoutItemTemplate>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal" >
<avalonDock:LayoutAnchorablePaneGroup DockWidth="" Orientation="Vertical" >
<avalonDock:LayoutAnchorablePane >
<avalonDock:LayoutAnchorable Title="left" ></avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
</avalonDock:LayoutAnchorablePaneGroup>
<avalonDock:LayoutPanel Orientation="Vertical" >
<avalonDock:LayoutDocumentPaneGroup Orientation="Horizontal">
<avalonDock:LayoutDocumentPane >
<avalonDock:LayoutDocument Title="main"></avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane> </avalonDock:LayoutDocumentPaneGroup>
<avalonDock:LayoutAnchorablePaneGroup DockHeight="" Orientation="Horizontal" >
<avalonDock:LayoutAnchorablePane >
<avalonDock:LayoutAnchorable Title="bottom" ></avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
</avalonDock:LayoutAnchorablePaneGroup>
</avalonDock:LayoutPanel>
<avalonDock:LayoutAnchorablePaneGroup DockWidth="" Orientation="Horizontal" >
<avalonDock:LayoutAnchorablePane >
<avalonDock:LayoutAnchorable Title="Right" ></avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
</avalonDock:LayoutAnchorablePaneGroup>
</avalonDock:LayoutPanel> </avalonDock:LayoutRoot>
</avalonDock:DockingManager>
</Grid>
</Grid>
</UserControl>
这是VS2012设计器的显示
这些东西的学习周期还是有的,我就不一一去说。有些东西只可意会不可言传。
DockViewModel
[Export(typeof(IScreen))]
public class DockViewModel : Screen
{ }
我们可以看到ShellViewModel里的DockContent就是IScreen类型的,由于标记为Import,所以程序会自动帮我们把MEF容器里IScreen类型注入,所以其实DockContent就是DockView,我这里为了方便直接用了CM框架的IScreen,如果有两个类标记为[Export(typeof(IScreen))],就会导致程序异常,因为有两个实例。程序不知道该导出哪个,所以我们之后会定义另一个接口,该接口只有唯一一个类即唯一的DockViewModel标记为导出,因为我们DockView就是唯一的,导入和导出部件这是MEF的知识,MEF是什么大家可以百度学习,CM框架默认是MEF作为容器。
MEF
Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)以及Duck Typing等。MEF为开发人员提供了一个工具,让我们可以轻松的对应用程序进行扩展并且对已有的代码产生最小的影响,开发人员在开发过程中根据功能要求定义一些扩展点,之后扩展人员就可以使用这些扩展点与应用程序交互;同时MEF让应用程序与扩展程序之间不产生直接的依赖,这样也允许在多个具有同样的扩展需求之间共享扩展程序
第一阶段就先这样,以后我会慢慢更新,直道整个插件系统的完成
如果您看了本篇博客,觉得对您有所收获,请点击右下角的 [推荐]
如果您想转载本博客,请注明出处
如果您对本文有意见或者建议,欢迎留言
感谢您的阅读,请关注我的后续博客
作者:Zengg 出处:http://www.cnblogs.com/01codeworld/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(一)的更多相关文章
- AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(菜单篇)
这章主要说插件的菜单,可以说菜单是最核心的部分,前面我们已经实现了Document添加,现在主要就是生成具有层级关系的菜单,以及把菜单跟我们自定义的Document关联起来,也就是MenuPart-& ...
- AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(二)
上次已经建立了可运行的基本框架,这篇就说说怎么把我们自定义的View自动加载并添加到AvalonDock里面,AvalonDock里有3种类型的UI部件,Document, DockableConte ...
- Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(翻译)
Caliburn.Micro 杰的入门教程1(翻译)Caliburn.Micro 杰的入门教程2 ,了解Data Binding 和 Events(翻译)Caliburn.Micro 杰的入门教程3, ...
- 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器
从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器 之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Calibu ...
- WPF +MVVM(Caliburn.Micro)项目框架
最近做了一个软件,这个软件不是网站,但是与HTML,AJAX等技术密切相关,也不是只有单纯的数据库增删改查,还涉及到线程协调,比较复杂的文本处理…… 这样的软件,用OA,ERP的框架显然是不合适的,因 ...
- Caliburn.Micro学习笔记(一)----引导类和命名匹配规则
Caliburn.Micro学习笔记目录 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeplex.com/ 文档也写的很详 ...
- Caliburn.Micro学习笔记(二)----Actions
Caliburn.Micro学习笔记目录 上一篇已经简单说了一下引导类和简单的控件绑定 我的上一个例子里的button自动匹配到ViewModel事件你一定感觉很好玩吧 今天说一下它的Actions, ...
- Xamarin 的 MVVM 之 Caliburn.Micro
约定 Caliburn.Micro 以下简称 CMXamarin.Form 以下简称 XF 摘要CM 当前已释出 3.0 beta 版https://github.com/Caliburn-Micro ...
- 开源框架Caliburn.Micro
Caliburn.Micro学习笔记----引导类和命名匹配规则 用了几天时间看了一下开源框架Caliburn.Micro 这是他源码的地址http://caliburnmicro.codeple ...
随机推荐
- 【转】利用MVC模式开发Java应用程序[组图]
Java是一种面向对象的语言,是实现面向对象编程的强大工具.我们在实际编程中,应该运用并发挥其最大效能.但是,要利用面向对象编程思想,自己独立开 发出好的Java应用程序,非凡是大.中型程序,并不是一 ...
- jQuery之DOM操作
对于DOM的认知,我们了解多少? DOM是Document Object Model的缩写,意思是文档对象模型,是由W3C制定的一套访问和操作XML(eXtensible Markup Languag ...
- IOS小知识纪录
1.scrollView缩放 #import "ViewController.h" @interface ViewController () <UIScrollViewDel ...
- VHDL MOD和REM(转)
mod(取模)and rem(取余) VHDL has mod and rem. They return the same value if both arguments are positive. ...
- iOS中—触摸事件详解及使用
iOS中--触摸事件详解及使用 (一)初识 要想学好触摸事件,这第一部分的基础理论是必须要学会的,希望大家可以耐心看完. 1.基本概念: 触摸事件 是iOS事件中的一种事件类型,在iOS中按照事件划分 ...
- jquery里用each遍历的值存到数组和字符串
$("img").each(function(){ var a = $(this).attr("src"); }); //遍历后存放到数组中..要用的时候再根据 ...
- ArcGIS Desktop开发基础(转)
http://www.cnblogs.com/maweifeng/archive/2006/07/19/455024.html 原文地址 ArcGIS Desktop开发的类型 ○ 自定义ArcMa ...
- 试写Python内建函数range()
还没查阅源码,先试着练手 class my_range(object): def __init__(self, *args): if not args: raise TypeError, 'range ...
- 为一个有数据没有主键id的数据表添加主键字段
ALTER TABLE `photo_feedbacks` ADD COLUMN `id` int(11) NOT NULL AUTO_INCREMENT FIRST ,ADD PRIMARY KE ...
- 14种网页jQuery和css3特效插件代码演示
1.网页table增删样式代码 演示和下载地址 2.jQuery左右滑动幻灯片插件 演示和下载地址 3.jQuery文字轮播焦点图 演示和下载地址 4.网页文字焦点图切换 演示和下载地址 5.jQue ...