[WPF] MVVM Plugin模式
动机 :
Plugin是在软件系统内增加功能的功能。
如果在软件系统加入Plugin功能,能提高软件系统的重用性。
加入Plugin功能的软件系统在开发完成之后。
如果需要额外加入功能,不用变更已完成的软件系统就能加入新功能。
并且因为不用变更已完成的软件系统,也就避免了修改软件系统会产生的风险。
在MVVM的架构下View跟ViewModel各自独立,做Plugin功能也就变得比较复杂。
必须要View跟ViewModel各自都有Plugin功能然后再互相组合,才能完成MVVM Plugin的功能。
本篇文章记录在WPF上,如何实做MVVM Plugin。
为自己做个纪录,也希望能帮助到有需要的开发人员。
结构 :
首先我们来看下图,说明了MVVM Plugin的结构。
图中说明了整个结构包含的项目,并且也可以看到它们之间的相依关系。
而MvvmPlugin.dll是整个Plugin的主要系统,MvvmPlugin.View与MvvmPlugin.ViewModel则是,主要系统之外要挂载的部份。
接着看看下面两张图,说明了MvvmPlugin.dll的对象跟画面。
由图中可以看出来,整个项目里的对象。
可以分成两大类,分别代表MVVM的View跟ViewModel。
代表View的部份负责实做,画面如何呈现的功能。
代表ViewModel的部份是实做,画面要呈现甚么。
在View跟ViewModel之间,则是用WPF的Binding功能来做连接。
而在ViewModel里面,也可以看到是由AnchorViewModel来负责建立IWorkspaceViewModel。
并且窗体画面会划分为两个区块,
左边区块里的<<WPF ItemsControl>>
-显示所系结的所有<<class>>AnchorViewModel。
-只要增加<<class>>AnchorViewModel的数量,就会增加画面上的按钮数量。
-使用<<WPF ItemTemplate>>来显示系结的<<class>>AnchorViewModel。
右边区块里的<<WPF ContentControl>>
-则会显示所系结的一个<<inteface>>IWorkspaceViewModel。
-只要换掉<<inteface>>IWorkspaceViewModel的对象,就会变更画面上的窗体。
回头看上一段落右边区块的说明,会发现没有描述<<inteface>>IWorkspaceViewModel采用甚么Template来显示。
我们另外再参考下一张的图片说明,
可以看到<<WPF ContentControl>>,使用外部Template来显示系结的<<inteface>>IWorkspaceViewModel。
至于系统里有哪些外部Template、<<inteface>>IWorkspaceViewModel要用外部Template来显示,则是由<<xaml>>MainWindow.view.config.xaml所设定。
而有哪些外部用来生成<<inteface>>IWorkspaceViewModel的<<class>>AnchorViewModel要显示,则是由<<xaml>>MainWindow.viewmodel.config.xaml来设定。
在这两个档案数据内加入新增功能的数据,就可以完成MVVM Plugin要加入功能的功能。
实做 :
范列下载 :
范例的程序代码较多,实做说明请参照范例程序内容。
范例程序点此下载
MvvmPlugin.dll :
MvvmPlugin.dll是整个系统的主要结构。
提供了可执行的应用程序外壳,并且也开放Plugin的功能用来挂载系统。
主要参与者有:
MainWindowViewModel
-整个系统的主要ViewModel。
-提供AnchorCollection及Workspace,给MainWindowView.xaml做Binding。
-收到AnchorViewModel发出的WorkspaceViewModel事件时,用新的WorkspaceViewModel替换旧的。
-使用XamlReader颇析外部MainWindow.viewmodel.config.xaml档案,当作AnchorCollection内容的来源。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | //使用XamlReader颇析外部MainWindow.viewmodel.config.xaml档案,当作AnchorCollection内容的来源。 private IEnumerable<AnchorViewModel> CreateAnchorCollection( string anchorConfigFile) { #region Require if ( string .IsNullOrEmpty(anchorConfigFile) == true ) throw new ArgumentNullException(); #endregion // Result List<AnchorViewModel> anchorList = new List<AnchorViewModel>(); // Create ResourceDictionary resourceDictionary = this .CreateResourceDictionary(anchorConfigFile); foreach ( object resource in resourceDictionary.Values) { AnchorViewModel anchorViewModel = resource as AnchorViewModel; if (anchorViewModel != null ) { anchorViewModel.WorkspaceOpened += delegate (IWorkspaceViewModel workspace) { IWorkspaceViewModel oldWorkspace = this .Workspace; this .Workspace = workspace; if (oldWorkspace != null ) oldWorkspace.Dispose(); }; anchorList.Add(anchorViewModel); } } // return return anchorList; } private ResourceDictionary CreateResourceDictionary( string resourceDictionaryFile) { #region Require if ( string .IsNullOrEmpty(resourceDictionaryFile) == true ) throw new ArgumentNullException(); #endregion // Require if (File.Exists(resourceDictionaryFile) == false ) throw new ArgumentException( string .Format( "File is not existed : {0}" , resourceDictionaryFile)); // Create ResourceDictionary FileStream fileStream = new FileStream(resourceDictionaryFile, FileMode.Open); ResourceDictionary resourceDictionary = XamlReader.Load(fileStream) as ResourceDictionary; // Return return resourceDictionary; } |
MainWindow.xaml
-整个系统的主要View。
-直接在xaml内,建立MainWindowViewModel并且绑定。
-与MainWindowViewModel提供的AnchorCollection及Workspace,做Binding。
-参考外部ResourceDictionary的方式,读取MainWindow.view.config.xaml,作为Binding WorkspaceViewModel的Template。
1 2 3 4 5 6 7 8 9 | <!--参考外部ResourceDictionary的方式,读取MainWindow.view.config.xaml--> < Window.Resources > < ResourceDictionary Source="pack://siteoforigin:,,,/MainWindow.view.config.xaml" /> </ Window.Resources > <!--直接在xaml内,建立MainWindowViewModel并且绑定--> < Window.DataContext > < MvvmPlugin:MainWindowViewModel /> </ Window.DataContext > |
IWorkspaceViewModel
-挂载进MvvmPlugin.dll的外部WorkspaceViewModel,要实做的接口。
-与外部Template做Binding来显示。
AnchorViewModel
-挂载进MvvmPlugin.dll的外部AnchorViewModel,要实做的接口。
-提供Title、ExecuteCommand,给MainWindowView.xaml做Binding。
-触发时建立新的WorkspaceViewModel,发出事件通知MainWindowViewModel。
MvvmPlugin.ViewModel.dll、MvvmPlugin.View.dll :
MvvmPlugin.ViewModel.dll是要挂载的ViewModel实做,职责除了提供要挂载进系统的功能之外也负担了如何生成的职责。
MvvmPlugin.ViewModel.dll是要挂载的View实做,职责主要是提供Binding的ViewModel的外观。
之所以没有将这两个项目做合并,是为了突显在MVVM架构下View是可以独立做抽换的。
主要参与者有:
AAnchorViewModel
-负责生成要挂载的ViewModel
AWorkspaceViewModel
-实际要挂载的ViewModel
AWorkspaceView.xaml
-实际要挂载的View
后记 :
在这个模式里,其实还少了一块Model的Plugin功能。
因为Model的Plugin这个功能,相对于MVVM Plugin是比较独立的模式。
在后续的文章里,将会有Model Plugin的独立介绍。
期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?