通过之前的介绍大家都知道我们可以做好插件,直接在界面调用即可;那么我们界面插件如何读取其他插件的信息并生成相应的菜单呢?下面开始介绍:
我们通过一个现有的简单winform的界面插件来学习界面插件如何制作。首先创建一个高级windows窗体主应用程序。
运行程序,在插件仓库中下载该插件——简单winform通用窗体插件;安装成功之后运行。效果如下:
大家可以看到该程序有一些菜单,这些菜单都是一个个的插件,那么咱们的这个程序是如何将插件加载进来的呢?这是咱们主要要学习的地方,把加载机制学会了,以后才能即使用自己的界面又能用灵活的插件。
下面咱们分析一下,上篇博客中说了,是通过Manifest文件加载的菜单;主要是解析了Extension point节点下的Application;我们来看看如何做到解析Manifest文件。该源码可从官网上下载。
1.创建拓展模型
这个界面框架通过OSGi.NET的扩展点-扩展机制实现了界面的扩展,允许其它插件通过定义扩展的方式将界面元素注册到该界面框架。这个框架接受的扩展配置如下所示。扩展点名称为UIShell.Applications,底下是Application和Menu定义。Application对应于界面菜单的根节点,Menu表示这个插件的所有菜单配置,支持嵌套方式。每个Menu可以定义一个Class属性,表示点击这个菜单时,在内容区域显示的窗体或者用户控件全名称。
2.创建拓展模型对象
现在定义相应的拓展对象,看源码ExtensionModel目录下有3个文件,WinShellApplication和WinShellMenu对应Extension信息里面的Application和MenuXML节点配置,WinShellApplicationContainer是WinShellApplication对象容器。下面我们看一下:
WinShellApplicationContainer核心代码如下:
(1)将一个扩展转换成WinShellApplication对象,并添加到缓存,然后返回该对象 :
/// <summary>
/// 将一个扩展转换成WinShellApplication对象。
/// </summary>
/// <param name="extension">指定的扩展对象。</param>
/// <returns>返回的WinShellApplication对象。</returns>
public WinShellApplication AddApplicationForExtension(Extension extension)
{
WinShellApplication app = null;
List<XmlNode> data = extension.Data;
if (data != null && data.Count > 0)
{
// 1 将扩展的Application XML节点转换成WinShellApplication对象。
XmlNode topNode = data[0];
if (topNode.NodeType == XmlNodeType.Element && topNode.Attributes != null && topNode.Attributes["Title"] != null)
{
string appTitle = topNode.Attributes["Title"].Value;
string appToolTip = topNode.Attributes["ToolTip"].Value;
string appIcon = topNode.Attributes["Icon"].Value;
if (!string.IsNullOrEmpty(appTitle))
{
string parentGuid = Guid.NewGuid().ToString();
int topNodeLevel = 0;
app = new WinShellApplication(appTitle, appToolTip, appIcon, extension.Owner);
// 2 递归的将扩展的Menu XML节点及其子节点转换成WinShellMenu对象。
CreateWinShellMenusFromXmlNode(app.Menus, app, null, topNode, topNodeLevel);
// 3 将Application对象保存起来。
_instance.AddApplication(app);
}
}
}
return app;
}
(2)删除Extension对应的WinShellApplication对象:
/// <summary>
/// 删除Extension对应的WinShellApplication。
/// </summary>
/// <param name="extension">指定的Extension。</param>
/// <returns>删除的WinShellApplication对象。</returns>
public WinShellApplication RemoveApplicationForExtension(Extension extension)
{
var app = GetWinShellApplication(extension.Owner);
if (app != null)
{
RemoveApplication(app);
}
return app;
}
(3)获取一个插件注册的扩展信息对应的WinShellApplication对象:
/// <summary>
/// 获取指定插件的WinShellApplication对象。
/// </summary>
/// <param name="bundle">指定插件。</param>
/// <returns>WinShellApplication对象。</returns>
public WinShellApplication GetWinShellApplication(IBundle bundle)
{
foreach (WinShellApplication app in Applications)
{
if (app.Bundle.Equals(bundle))
return app;
}
return null;
}
(4)获取一个插件注册的扩展信息对应的一级菜单列表: /// <summary>
/// 获取指定插件的顶层菜单对象。
/// </summary>
/// <param name="bundle">指定插件。</param>
/// <returns>顶层菜单对象集合。</returns>
public List<WinShellMenu> GetTopWinShellMenus(IBundle bundle)
{
WinShellApplication app = GetWinShellApplication(bundle);
if (app != null)
return app.Menus;
return null;
}
(5)将扩展的Menu对应的XML节点解析成WinShellMenu对象集合:
/// <summary>
/// 将扩展的Menu对应的XML节点解析成WinShellMenu集合。
/// </summary>
/// <param name="menus">顶层WinShellMenu集合。</param>
/// <param name="application">所属的WinShellApplication。</param>
/// <param name="parent">父菜单。</param>
/// <param name="topNode">顶层XML节点。</param>
/// <param name="nodeLevel">XML节点层次。</param>
private void CreateWinShellMenusFromXmlNode(List<WinShellMenu> menus, WinShellApplication application, WinShellMenu parent, XmlNode topNode, int nodeLevel)
{
if (menus == null)
{
menus = new List<WinShellMenu>();
}
foreach (XmlNode childNode in topNode.ChildNodes)
{
if (childNode.NodeType == XmlNodeType.Element)
{
string type = null;
if (childNode.Attributes["Class"] != null)
type = childNode.Attributes["Class"].Value;
string text = childNode.Attributes["Text"] == null ? string.Empty : childNode.Attributes["Text"].Value;
string toolTip = childNode.Attributes["ToolTip"] == null ? string.Empty : childNode.Attributes["ToolTip"].Value;
string icon = childNode.Attributes["Icon"] == null ? string.Empty : childNode.Attributes["Icon"].Value;
string guid = Guid.NewGuid().ToString();
// 创建WinShellMenu对象。
WinShellMenu winShellMenu = new WinShellMenu(application, parent, text, toolTip, icon, type, nodeLevel, guid);
menus.Add(winShellMenu);
// 递归创建子节点对象。
int childNodeLevel = nodeLevel + 1;
CreateWinShellMenusFromXmlNode(winShellMenu.Children, application, winShellMenu, childNode, childNodeLevel);
}
}
}
WinShellApplication类对应扩展的ApplicationXML节点,其Title、ToolTip、Icon属性对应XML相应属性,Bundle表示定义这个节点的插件,Menus表示子菜单集合。
WinShellMenu类对应扩展的MenuXML,其Text、ToolTip、Icon属性对应相应XML属性,ClassName对应Class属性,Application表示所属的WinShellApplication对象,Parent表示父菜单对象,Children表示子菜单对象列表。
建立扩展模型后,我们接着要来创建一个主界面了。
现在我们把用到的基础类讲解了,下篇博客中我们来看看到底如何设计插件界面的界面,敬请期待。。。