AvalonDock 2.0+Caliburn.Micro+MahApps.Metro实现Metro风格插件式系统(一)

article/2025/9/24 21:52:22
随着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="500" Width="800"><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="0"/></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="300" d:DesignWidth="800"><UserControl.Resources><avalonDock:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/></UserControl.Resources><Grid><Grid x:Name="layoutRoot"><avalonDock:DockingManager  Grid.Row="1" 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="200"    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="100"   Orientation="Horizontal"  ><avalonDock:LayoutAnchorablePane  ><avalonDock:LayoutAnchorable Title="bottom" ></avalonDock:LayoutAnchorable></avalonDock:LayoutAnchorablePane></avalonDock:LayoutAnchorablePaneGroup></avalonDock:LayoutPanel><avalonDock:LayoutAnchorablePaneGroup DockWidth="200"    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/


http://chatgpt.dhexx.cn/article/nNKD6Dft.shtml

相关文章

WPF实现选项卡效果(2)——动态添加AvalonDock选项卡

原文: WPF实现选项卡效果&#xff08;2&#xff09;——动态添加AvalonDock选项卡 简介 在前面一篇文章里面&#xff0c;我们使用AvalonDock实现了类似于VS的选项卡&#xff08;或者浏览器的选项卡&#xff09;效果。但是我们是通过xaml代码实现。   现在我们尝试通过C#代码…

Microsoft.Windows.Controls.Ribbon.RibbonWindow 碰到 AvalonDock出现的诡异现象

部分一 14年底进入目前公司时&#xff0c;领导准备开发一款新软件平台以取代原有平台。原平台采用CBuild开发界面(window c/s客户端) 、Visual Studio(封装dll模块)。过完年&#xff0c;领导已把框架搭建完毕(过年期间领导加班了 _ )。当时菜鸟一个(目前老鸟了)&#xff0c;新…

WPF实现选项卡效果(1)——使用AvalonDock

WPF实现选项卡效果&#xff08;1&#xff09;——使用AvalonDock 原文: WPF实现选项卡效果&#xff08;1&#xff09;——使用AvalonDock 简介 公司最近一个项目&#xff0c;软件采用WPF开发&#xff0c;需要实现类似于VS的选项卡(或者是浏览器的选项卡)效果。搜寻诸多资料后&a…

AvalonDock使用(2)-简单布局设置

在上一篇《AvalonDock的基本用法》中&#xff0c;我们使用AvalonDock控件&#xff0c;简单实现了&#xff0c;停靠左右两边的面板&#xff1b;这是面板的默认停靠位置&#xff1b;当然你也可以拖动它&#xff0c;让浮动&#xff0c;也可以让它停靠在其它地方&#xff1b; 通过简…

wpf-AvalonDock-使用技巧总结

LayoutAnchorable展示时的宽度 开始时LayoutAnchorable是隐藏的&#xff0c;控制展示时的宽度用 <avalondock:LayoutAnchorable Title"描述信息" AutoHideWidth"300">

Avalondock 第四步 边缘停靠

前一章介绍了分组功能&#xff0c;这一章主要介绍细节信息&#xff0c;LayoutRoot的side属性 LayoutRoot包含四个属性&#xff0c;LeftSide&#xff0c;RightSide,TopSide,BottomSide,分别用于展示DockingManager中左右上下四个位置的内容&#xff0c;但初始状态为隐藏状态。 …

Avalondock 第二步 创建文档面板

Avalondock 第二步 创建文档面板 上一篇已经介绍了如何创建一个停靠面板&#xff0c;本章主要介绍&#xff0c;文档面板的定义。文档面板和可停靠面板很相似 建立文档面板LayoutDocumentPane LayoutDocumentPane:文档窗格类&#xff0c;与LayoutAnchorablePane类似&#xff…

【AvalonDock】布局控件使用教程

1、Nuget 包 XceedProucts.Wpf.Toolkit.AvalonDock 包安装 2、安装完成&#xff0c;项目会引入这两个dll 3、在MainWindows窗体中引入命名空间 xmlns:avalon"http://schemas.xceed.com/wpf/xaml/avalondock" 4、Avalon 布局。 靠边隐藏窗口 LayoutRoot.LeftSid…

Avalondock 技巧之如何隐藏浮动面板停靠器

avalondock 技巧之如何隐藏浮动面板停靠器 之前开发的一个项目需要实现窗口的浮出&#xff0c;拖拽&#xff0c;停靠等功能&#xff0c;于是想到了神器Avalondock&#xff0c;这个框架功能相当强大&#xff0c;而且能实现多种主题样式的控件&#xff0c;特别是窗口的浮动停靠等…

[转]AVALONDOCK 2.0入门指南第一部分

AvalonDock 2.0可以用来为WPF创建一个类似Visual Studio的界面&#xff0c;深入理解如何使用AvalonDock进行开发是很重要的。 在这个入门指南里&#xff0c;我将演示如何开始使用AvalonDock&#xff0c;下面的文章都是基于2.0版本的。并且不能用于早期的版本。 AvalonDock是一个…

WPF AvalonDock拖拽布局学习整理

AvalonDock提供了一个系统&#xff0c;允许开发人员使用类似于许多流行的集成开发环境&#xff08;IDE&#xff09;中的窗口对接系统来创建可自定义的布局。 AvalonDock遵循MVVM设计。Model由Xceed.Wpf.AvalonDock.Layout命名空间中包含的类表示。此命名空间中的类是布局模型中…

WPFAvalonDock基本用法

本文简单介绍AvalonDock2.0基本用法&#xff0c;下载AvalonDock 2.0dll及主题http://avalondock.codeplex.com/ AvalonDock基本类介绍 DockingManager:停靠管理类&#xff0c;xaml中AvalonDock的根节点 LayoutRoot:布局根节点&#xff0c;有四个属性LeftSide,RightSide,TopS…

AvalonDock的基本用法

AvalonDock是优秀的开源项目&#xff0c;用于创建可停靠式布局&#xff0c;能够在WPF中方便开发出类似VS2010的软件界面。对于复杂的软件系统&#xff0c;大量控件的使用会使的界面变得难以管理。AvalonDock帮我们解决了这一问题。想要在WPF项目中使用AvalonDock的功能&#xf…

WPF随笔(十)--使用AvalonDock实现可停靠式布局

我们每天使用的许多软件都使用了可停靠式布局&#xff0c;可以方便的打开、关闭、收起、展开、移动选项卡。今天就来说明如何使用AvalonDock实现这种可停靠式布局。 AvalonDock安装 最新版本的AvalonDock类库包含在程序包Extended.Wpf.Toolkit中&#xff0c;属于Xceed旗下的一…

WPF AvalonDock 常用功能使用

AvalonDock是什么&#xff1f; AvalonDock是一个开源项目【GitHub - Dirkster99/AvalonDock: Our own development branch of the well known WPF document docking libraryGitHub - Dirkster99/AvalonDock: Our own development branch of the well known WPF docume…

WPF 第三方控件学习使用——可停靠布局控件(AvalonDock)

需求 近期在做公司上位机产品规划与实验&#xff0c;参考了Blender软件的布局风格&#xff0c;希望能用WPF也做一个类似布局的上位机。于是开始寻找资源&#xff0c;很快就发现了AvalonDock。 AvalonDock简介 AvalonDock是Xceed公司 Wpf.Toolkit 中的一款收费产品&#xff0…

wpf-AvalonDock基础-安装和更换主题

2022/7/29更新&#xff1a;去掉标题行的钉子 在LayoutAnchorable上添加属性&#xff1a; CanAutoHide"False" CanClose"False"如果要去掉X&#xff0c;再添加 CanHide"False"最近对wpf的多窗口排列问题深感头疼&#xff0c;算尺寸、位置太麻烦…

AvalonDock使用(1)-基本用法

AvalonDock的基本用法 介绍AvalonDock库中的基本类DockingManager&#xff1a;停靠管理器类LayoutRoot : 布局根节点类LayoutPanel&#xff1a;布局面板类LayoutAnchorablePane&#xff1a;可停靠窗格类LayoutAnchorable:可停靠内容类 LayoutDocumentPane:文档窗格类LayoutDocu…

十进制-75在计算机中,十进制数75转换成二进制数是多少?

75转换成二进制是&#xff1a;1001011。 75/237......1 37/218......1 18/29.........0 9/24...........1 4/22...........0 2/21...........0 从下往上读余数&#xff0c;就是整数部分的案1001011。拓展资料&#xff1a; 十进制整数转换为二进制整数方法&#xff1a; 十进制整…

二进制数的算术运算

2&#xff0c; 二进制数的算术运算 2.1 二进制数的算术运算 二进制数的算术运算包括加法、减法、乘法和除法。 1)加法运算 加法进位规则:逢二进一。 加法运算法则: 000 01101 1110(向高位进位) 例:(1101)2(1011)2?&#xff0c;解算如下: 从执行加法的过程可知&…