OSGI(六)界面插件制作2

       上篇博客中,我们讲解了创建拓展模型和创建拓展模型对象,下面我们继续介绍,完成后面的步骤。

1.创建主界面:

OSGI(六)界面插件制作2_第1张图片

      主界面为上下布局,上部分是一个MenuStrip,下部分是一个TabControl。下面我们将通过OSGi.NET的扩展机制,将其它插件注册的扩展信息转换成这个主界面的菜单项。

 

2.处理扩展点,将扩展信息转换成界面元素

 

       首先,我们先看一下如何获取扩展信息并监听事件。代码如下,在HandleExtension方法中,我们通过BundleContext插件上下文的GetExtensions来获取界面框架定义的扩展点的所有已有扩展信息,然后通过ApplicationContainer将扩展转换成WinShellApplication对象,并为其创建相应菜单,接着监听扩展变更事件。

         /// <summary>
        /// 处理扩展信息。
        /// </summary>
        private void HanldeExtension()
        {
            Initialize();

            // 1 获取所有扩展信息
            var extensions = BundleContext.GetExtensions(SimpleWinFormShellExtensionPoint);
            WinShellApplication application;

            foreach (var extension in extensions)
            {
                // 2 将扩展Extension对象转换成WinShellApplication对象
                application = ApplicationContainer.AddApplicationForExtension(extension);
                // 3 为WinShellApplication对象创建顶层菜单和子菜单
                CreateMenuStripForApplication(application);
            }
            // 4 监听扩展变更事件
            BundleContext.ExtensionChanged += BundleContextExtensionChanged;
        }

           其次,是扩展变更事件处理的代码,当插件启动时,其扩展信息注册到OSGi.NET内核,当插件卸载时,其扩展信息会被卸载掉,因此当扩展信息新增时,我们需要为其创建菜单项;反之,需要删除菜单项和已经显示的内容。

   private void BundleContextExtensionChanged(object sender, ExtensionEventArgs e)
        {
            if (e.ExtensionPoint.Equals(SimpleWinFormShellExtensionPoint))
            {
                if (e.Action == CollectionChangedAction.Add)
                {
                    // 新增扩展信息,说明有插件被启动,为其创建界面菜单
                    var app = ApplicationContainer.AddApplicationForExtension(e.Extension);
                    CreateMenuStripForApplication(app);
                }
                else if (e.Action == CollectionChangedAction.Remove)
                {
                    // 扩展信息被删除,有插件被停止,删除对应的界面菜单
                    var app = ApplicationContainer.RemoveApplicationForExtension(e.Extension);
                    RemoveMenuStripForApplication(app);
                }
            }
        }

      下面我们看一下为WinShellApplication创建相应界面元素的代码,这里我们利用该对象创建了一个顶层菜单项和所有子菜单项。 

        /// <summary>
        /// 扩展变更事件是一个异步事件,即是一个新的线程来处理事件。
        /// 因此,需要将扩展变更事件对界面的变更通过代理发送到界面
        /// 线程,由其来更新界面。
        /// </summary>
        /// <param name="application">应用对象。</param>
        private delegate void CreateMenuStripForApplicationDelegate(
            WinShellApplication application);

        private void CreateMenuStripForApplication(WinShellApplication application)
        {
            CreateMenuStripForApplicationDelegate del = (WinShellApplication app) =>
            {
                // 为WinShellApplication创建根菜单节点
                var topToolStripItem = TopMenuStrip.Items.Add(app.Title,
                    LoadImage(app.Bundle, app.Icon)) as ToolStripMenuItem;

                topToolStripItem.ToolTipText = app.ToolTip;

                // 创建子菜单节点
                CreateChildMenu(app.Menus, topToolStripItem.DropDownItems);
                // 添加到WinShellApplication和顶层菜单节点对应表
                ApplicationMenuStripMap.Add(app, topToolStripItem);
            };

            // 如果当前线程不是界面线程,则通过Invoke来处理界面变更
            if (InvokeRequired)
            {
                Invoke(del, application);
            }
            else // 否则,直接操作界面
            {
                del(application);
            }
        }

       最后是移除界面元素的源码。

        /// <summary>
        /// 扩展变更事件是一个异步事件,即是一个新的线程来处理事件。
        /// 因此,需要将扩展变更事件对界面的变更通过代理发送到界面
        /// 线程,由其来更新界面。
        /// </summary>
        /// <param name="application">应用对象。</param>
        private delegate void RemoveMenuStripForApplicationDelegate(WinShellApplication application);

        private void RemoveMenuStripForApplication(WinShellApplication application)
        {
            RemoveMenuStripForApplicationDelegate del = (WinShellApplication app) =>
            {
                if (ApplicationMenuStripMap.ContainsKey(app))
                {
                    // 删除菜单、Map、显示的TabPage
                    TopMenuStrip.Items.Remove(ApplicationMenuStripMap[app]);
                    ApplicationMenuStripMap.Remove(app);
                    foreach (TabPage tab in WorkspaceTabControl.TabPages)
                    {
                        var menu = tab.Tag as WinShellMenu;
                        if (menu.Application.Equals(app)) // 清除Selection
                        {
                            var index = WorkspaceTabControl.SelectedIndex;
                            if (index > 0 && tab.Equals(WorkspaceTabControl.SelectedTab))
                            {
                                WorkspaceTabControl.SelectedIndex = index - 1;
                            }
                            WorkspaceTabControl.TabPages.Remove(tab);
                        }
                    }
                }
            };
            // 如果当前线程不是界面线程,则通过Invoke来处理界面变更
            if (InvokeRequired)
            {
                Invoke(del, application);
            }
            else // 否则,直接操作界面
            {
                del(application);
            }
        }
    }


总结:

     下面总结一下如何做界面插件:

          首先创建一个插件程序---ExtensionModel文件夹中的3个基础类添加进来——添加界面窗体——编写界面窗体代码。用代码展示为:

创建一个空windows窗体或高级windows窗体,在program.cs文件中加入以下代码,作为程序的入口点;

OSGI(六)界面插件制作2_第2张图片

       添加一个Windows窗体插件程序,以下代码操作都是该类库中的操作。

     通过RunformInstance)找到插件的MainForm窗体,实例化,因为是界面插件所以要处理节点(即之前提过的扫描Manifest文件,通过其内容动态加载菜单)。

OSGI(六)界面插件制作2_第3张图片


   看一下HanldeExtension()方法,步骤很清楚先实例化在获取拓展信息;

OSGI(六)界面插件制作2_第4张图片


1.解析拓展点的名称、初始化基本工作:

OSGI(六)界面插件制作2_第5张图片

2.将一个扩展转换成WinShellApplication对象。

OSGI(六)界面插件制作2_第6张图片

3.WinshellApplication对象创建顶层菜单和子菜单

OSGI(六)界面插件制作2_第7张图片

4.拓展变更处理事件:

OSGI(六)界面插件制作2_第8张图片

        不管是windowsweb或其他应用程序,代码变动不大,只需要把相应的控件名称、控件加载的个别属性更改一下即可,用起来很方便。

        界面插件完成之后,我们将插件发布之后,真正主程序的目录如下截图:

OSGI(六)界面插件制作2_第9张图片

            很清晰,明了,通过Program.cs文件,加载插件,通过界面插件加载其他菜单,主程序只是一个容器,各个功能都是一个个的积木,搭起来就是一个多功能自定义的简单程序。通过这张图可以看出该程序的健壮性很好,即使某个插件不能用了,但是不会影响其他功能插件的使用。

Notice:

需要注意的是:我们做的界面插件的基础是iopenwork提供的UIShell.PageFlowService插件。我们通过引用该插件才能做响应的操作。

别忘了把这句代码放在该插件的Manifest文件中,否则插件界面不会显示加载。




      至此,界面插件制作介绍完成,不足之处敬请指正~~~~~~





你可能感兴趣的:(OSGI(六)界面插件制作2)