[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内容的来源。

//使用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。

<!--参考外部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的独立介绍。

posted @ 2012-02-05 15:32  Clark159  阅读(1968)  评论(0编辑  收藏  举报