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

  上次已经建立了可运行的基本框架,这篇就说说怎么把我们自定义的View自动加载并添加到AvalonDock里面,AvalonDock里有3种类型的UI部件,Document, DockableContent以及Floting类型,我主要说一下Document,DockableContent的添加,在AvalonDock里Document类型可参考VS,DockableContent相当于VS里的工具栏等,之后我直接在.cs文件里写注释以及解析。

现在的项目结构:

运行结果:

  

  可以看到里面多了一个测试的Document,该Document是由MEF自动加载并且绑定到AvalonDock里,这里我只写一个一个Document,有兴趣的可以自己动手试一试,目前的Document是写在主程序里面,其实这Document应该写在一个单独的DLL里面,这就是我们所谓的插件。 [BY Zengg]

DockScreenManager类  

 1 namespace UICoreFramework
 2 {
 3     /*DemoApplication里面的DockViewModel实现该接口,为了使全部的Documents以及DockableContents集中管理 */
 4     public interface IDockScreenManager
 5     {
 6         //用与绑定到AvalonDock的Document类型的数据源
 7         ObservableCollection<IDocument> Documents { get; }
 8         //用与绑定到AvalonDock的Document类型的数据源
 9         ObservableCollection<IDockableContent> DockableContents { get; }
10     }
11     public class DockScreenManager : ViewAware, IDockScreenManager
12     {
13         /// <summary>
14         /// ImportMany是MEF的知识,他的作用是把所有实现某个接口,并标记为Export的类全部倒入,
15         /// 相当于帮我们自动实例化并添加到List集合里
16         /// 
17         /// </summary>
18         [ImportMany]
19         public ObservableCollection<IDocument> Documents { get; set; }
20         [ImportMany]
21         public ObservableCollection<IDockableContent> DockableContents { get; set; }
22         public DockScreenManager()
23         {
24             
25         }
26     }
27 }
DockScreenManager

DocumentBase类

 1   /// <summary>
 2     /// Document的抽象类,一些抽象操作可以在里面写,为了方便我就没写东西
 3     /// DemoApplication的DocTestViewModel就是继承与该抽象类
 4     /// </summary>
 5     public abstract class DocumentBase : IDocument
 6     {
 7 
 8 
 9         public DockType Type
10         {
11             get
12             {
13                 throw new NotImplementedException();
14             }
15             set
16             {
17                 throw new NotImplementedException();
18             }
19         }
20 
21         public DockSide Side
22         {
23             get
24             {
25                 throw new NotImplementedException();
26             }
27             set
28             {
29                 throw new NotImplementedException();
30             }
31         }
32 
33 
34         public string DisplayName
35         {
36             get
37             {
38                 return "测试界面";
39             }
40             set
41             {
42                 throw new NotImplementedException();
43             }
44         }
45 
46         public bool IsNotifying
47         {
48             get
49             {
50                 throw new NotImplementedException();
51             }
52             set
53             {
54                 throw new NotImplementedException();
55             }
56         }
57 
58         public void NotifyOfPropertyChange(string propertyName)
59         {
60             throw new NotImplementedException();
61         }
62 
63         public void Refresh()
64         {
65             throw new NotImplementedException();
66         }
67 
68         public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
69     }
DocumentBase

IDockScreen接口

 1 namespace UICoreFramework
 2 {
 3     /// <summary>
 4     /// 只有DockableContent类型有位置的说法
 5     /// </summary>
 6     public enum DockSide
 7     {
 8         Left,
 9         Top,
10         Right,
11         Bottom
12     }
13     /// <summary>
14     /// Dock的类型
15     /// </summary>
16     public enum DockType
17     {
18         Document,
19         DockableContent,
20     }
21     /// <summary>
22     /// 抽象出基本的Content类型,并实现属性通知接口,因为以后绑定到AvalonDock是有双向绑定的,这样我们要操作AvalonDock时
23     /// 就可以直接操作实现该接口的属性,比如DisplayName的属性用于绑定到AvalonDock的LayoutItem的Title
24     /// </summary>
25     public interface IDockScreen:INotifyPropertyChangedEx
26     {
27         DockType Type { get; set; }
28         DockSide Side { get; set; }
29         string DisplayName { get; set; }
30     }
31 }
IDockScreen

IDocument接口

1 /// <summary>
2     /// 抽象出Document接口,暂时不写实际东西
3     /// </summary>
4     public interface IDocument : IDockScreen
5     {
6         
7     }
IDocument

PanesStyleSelector类

 1  /// <summary>
 2     /// 这个很重要,这是为使AvalonDock能区别Document和DockableContent类型并返回不同的style,两个类型不同style有不同的绑定属性
 3     /// 所以要区分开来
 4     /// </summary>
 5     public class PanesStyleSelector : StyleSelector
 6     {
 7         public Style ToolStyle
 8         {
 9             get;
10             set;
11         }
12 
13         public Style DocumentStyle
14         {
15             get;
16             set;
17         }
18         /// <summary>
19         /// 区别逻辑在这里写
20         /// </summary>
21         /// <param name="item">实现了IDocument或IDockableContent接口的实例</param>
22         /// <param name="container"></param>
23         /// <returns></returns>
24         public override Style SelectStyle(object item, DependencyObject container)
25         {
26             IDockScreen obj = (IDockScreen)item;
27             
28             if (item != null)
29             {
30                 //判定为什么类型
31                 if (item is IDocument)
32                 {
33                     return DocumentStyle;
34                 }
35                 else
36                 {
37                     return ToolStyle;
38                 }
39             }
40          
41             return base.SelectStyle(item, container);
42         }
43     }

较第一张更改部分:

  DockViewModel类

 1 namespace DemoApplication.Views
 2 {
 3     /// <summary>
 4     /// 字符串"DockViewModel"是为了标记唯一性,在ShellViewModel里导入时也要指定为"DockViewModel",这相当于一个key
 5     /// </summary>
 6     [Export("DockViewModel", typeof(IDockScreenManager))]
 7     public class DockViewModel : DockScreenManager
 8     {
 9         public DockViewModel()
10             : base()
11         {
12 
13         }
14     }
15 }

ShellViewModel类

 1 namespace DemoApplication
 2 {
 3     [Export(typeof(IShell))]
 4     class ShellViewModel : IShell
 5     {
 6         readonly IWindowManager windowManager;
 7         [ImportingConstructor]
 8         public ShellViewModel(IWindowManager windowManager)
 9         {
10             this.windowManager = windowManager;
11 
12         }
13         /// <summary>
14         /// DockView
15         /// </summary>
16         [Import("DockViewModel")]
17         public IDockScreenManager DockContent { get; set; }
18     }
19 }

MefBootstrapper类

 1  protected override void Configure()
 2         {
 3             /*CompositionContainer 对象在应用程序中有两种的主要用途。首先,它跟踪哪些部分可用于组合、它们的依赖项,并且充当任何指定组合的上下文。其次,它提供了应用程序可以启动组合的方法、获取组合部件的实例,或填充可组合部件的依存关系。
 4             部件可直接用于容器,或通过 Catalog 属性来用于容器。在此 ComposablePartCatalog 中可发现的所有部件都可以供容器来满足导入,还包括直接添加的任何部件。*/ 
 5             //container = new CompositionContainer(
 6             //    new AggregateCatalog(AssemblySource.Instance.Select(x => new AssemblyCatalog(x)))
 7             //    );
 8 
 9             
10             var catalog = new AggregateCatalog(
11                AssemblySource.Instance.Select(x => new AssemblyCatalog(x)).OfType<ComposablePartCatalog>()
12                );
13 
14             container = new CompositionContainer(catalog);
15 
16             var batch = new CompositionBatch();
17             var dockScreenManage = new DockScreenManager();
18             batch.AddExportedValue<IWindowManager>(new WindowManager());//將指定的导出加入至 CompositionBatch 物件
19             batch.AddExportedValue<IEventAggregator>(new EventAggregator());
20             batch.AddExportedValue<IDockScreenManager>(dockScreenManage);
21             batch.AddExportedValue(container);
22             batch.AddExportedValue(catalog);
23             container.Compose(batch);//在容器上执行组合,包括指定的 CompositionBatch 中的更改
24 
25             container.ComposeParts(container.GetExportedValue<IDockScreenManager>());//由于DockScreenManager里有标记为Import的字段,所以要在MEF容器里组装把指定的部件导入
26         }
MefBootstrapper

AvalonDock还支持其他几种皮肤,可以满足大众的需求:

AeroTheme

 ExpressionLightTheme

ExpressionDarkTheme

VS2010Theme

   DockableContent类型的实现和Document实现是一样的,只是实现的接口不同,DockableContent实现的是IDockableContent接口,具体请参考Document实现,有疑问的可以提出来,尽量帮助解决,解释写得略简单不好意思,但是有源码参考,如果源码对大家有帮助的话,求个推荐,回复或粉的神马的都好。。。

源码地址:

http://pan.baidu.com/share/link?shareid=819683340&uk=554439928

 

 

如果您看了本篇博客,觉得对您有所收获,请点击右下角的 [推荐]

如果您想转载本博客,请注明出处

如果您对本文有意见或者建议,欢迎留言

感谢您的阅读,请关注我的后续博客

作者:Zengg 出处:http://www.cnblogs.com/01codeworld/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

posted on 2013-06-26 20:39  Zengg  阅读(4176)  评论(15编辑  收藏  举报