SharpDevelop浅析_1_AddInTree 使用ICSharpCode.Core创建插件支持的应用程序
来源:百度文库 编辑:神马文学网 时间:2024/04/30 09:16:22
Demo运行界面:
使用AddIn好处:
AddIn实现分析:
SharpDevelop重要概念
Demo代码分析
总结:
相关资料:
Demo下载
1、Demo运行界面:
程序初始运行界面如下:
添加插件界面如下:
添加插件后界面如下:
运行环境:VS2005
2、使用AddIn好处
方便扩展,可以看到SharpDevelop几乎是通过插接功能模块组装而成;核心可以不必实现自己的定义,方便地通过接口扩充功能;插件dll可以放在任意位置,对插件使用拷贝、粘贴式的部署。
许多应用程序也使用了一些插件机制,但大多数局限于特定的功能,如扩展菜单或新文件格式。SharpDevelop插件体系的目标是为应用程序提供简单易用而又强大的扩展点,allowing AddIns to extend nearly everything.
3、AddIn实现分析:
简单分析后,实现思路是这样的:定义一个接口ICommand,声明void DoCommand()方法,新增插件必须实现此接口;
单击菜单项或工具栏按钮时需要与主窗体交互,这可以通过在ICommand中定义属性MainForm或在void DoCommand(MainForm frm)中增加方法参数来传递主窗体的引用,这些实现起来倒也简单。
接下来的问题是如何通知应用程序新增加了插件呢,答案是使用xml配置文件,怎么组织这个配置文件的结构呢?这个问题其实成了实现插件功能的重点和难点,配置文件中希望说明新增插件的dll位置、类名、插接入主程序的菜单还是工具栏项、插接位置,或许还希望配置文件更容易被扩展?
这里(http: //www.codeproject.com/cs/library/Net_AddinProjFrmwork.asp)有一个结构不太好的配置文件定义形式(可能也是我们简单分析后会想到的定义方式,可以看出结构固定,且不易扩展),大家可以自行分析下:
sample.xml
1
21
3Report Addin
41
5
6Bar Code
71
8
9Bar Code
101
11
12Test Menu
13AddinFunctionName
14Some Status bar text
15Some tool tip text
16Addin2Settings.ico
17Ctrl + H
18
19
20 ..
21 ..
22
23
24
25 ..
26 ..
27
28
29
30
31
32
33
现在来看看SharpDevelop的AddIn配置文件结构(参见Demo中的Entry.myAddins.Menus.addin):
Menus.addin
12 author = "michael zhang"
3 url = "http://www.cnblogs.com/michael-zhang/"
4 description = "基本插件"
5 addInManagerHidden = "true">
6
7
8
9
10
11
12
13
14
15
16
17
18
19
40
4142 tooltip = "Black command"
43 icon = "qq.face1"
44 class = "MainForm.CmdBlack"/>
45
4647 tooltip = "Exit the app"
48 icon = "CloseIcon"
49 class = "MainForm.CmdExit"/>
50
51
节提供了插件的名称、作者、url、插件描述等信息
提供了插件的唯一标识名称及版本,其它插件的配置文件可以引用该名称,如
指向该插件引用的dll位置
后面的形如... 的是定义配置文件的核心数据,path节的name属性指明该节下的节点所处(在AddInTree中)的命名层次,节点下的MenuItem, ToolBarItem, FileFilter, Include等统称为Condon,各代表菜单项、工具栏按钮、文件过滤等,这些数据结构可以非常简单地被扩展、解析。
注:
addin配置文件中的 label = "${res:Demo.Menu.File}", icon = "qq.face1" 等属性值是指向资源文件的引用,资源文件见Entry项目的StrImgRes.resx
4、SharpDevelop插件树中的重要概念
Condon: 代表节下的一个(一般化)节点(如:...)统称为 Condon,该类含ID、Name、InsertBefore、InsertAfter、Conditions、Properties(类似于 HashTable的结构)等属性,配置节中的其它属性(除ID,Name,InsertBefore,InsertAfter外,如label, shortcut等)存储在Properties对象中。
Doozer: 代表Condon节点的更具体的实例,如MenuItemDoozer, ToolBarItemDoozer, FileFilterDoozer, IncludeDoozer, FileFilterDoozer等,用以创建具体的object对象,可以扩展编写自定义的Doozer。
5、Demo项目代码分析
至此,我们大概能猜到SharpDevelop中的插件机制是怎样的,下面就结合Demo的分析来体验一下SharpDevelop的插件功能:
MainForm.FrmMain.cs中使用单件模式获取此类,关键代码如下:
FrmMain.cs
1using ICSharpCode.Core;
2
3// 变量声明
4const string _BoundProperty = "FormBounds";
5Label _lblMsg;
6MenuStrip _menuStrip;
7ToolStrip _toolStrip;
8//
9void IniFrm()
10{
11 // 设置窗体位置
12 Rectangle rect = PropertyService.Get(_BoundProperty, new Rectangle(10, 10, this.Width, this.Height));
13 this.StartPosition = FormStartPosition.Manual;
14 this.Bounds = rect;
15 this.FormClosing += delegate
16 {
17 // 设置用户属性信息
18 PropertyService.Set(_BoundProperty, this.Bounds);
19 };
20
21 _lblMsg = new Label();
22 _lblMsg.Dock = DockStyle.Fill;
23 _lblMsg.Font = new Font("Arial", 16, FontStyle.Bold);
24 _lblMsg.Text = "App loaded!";
25 this.Controls.Add(_lblMsg);
26
27 _toolStrip = ToolbarService.CreateToolStrip(this, "/michael/myToolbar");
28 this.Controls.Add(_toolStrip);
29
30 _menuStrip = new MenuStrip();
31 MenuService.AddItemsToMenu(_menuStrip.Items, this, "/michael/myMenus");
32 this.Controls.Add(_menuStrip);
33}
34public void DrawMsg(string msg,Color color)
35{
36 _lblMsg.Text = msg;
37 _lblMsg.ForeColor = color;
38}
主窗体的类中声明了Label, MenuStrip, ToolStrip 分别用以显示文字、菜单、工具栏。菜单、工具栏对象的获取通过ICSharpCode.Core内置类仅用简单的两行代码实现。此类中公开的 DrawMsg(...)方法用以向扩展菜单、工具栏按钮等提供公开可调用的功能。创建菜单、工具栏的两个方法中的一个重要参数是路径参数(分别是 "/michael/myToolbar"和"/michael/myMenus"),在前面的配置文件代码中可以找到相关定义节,其中相关节点一个重要属性是class, 该属性指定了(菜单、工具栏按钮的)相关类,其实现代码如下(MainForm项目的Commands.cs):
注:
FrmMain 类的IniFrm()方法中前几行代码用以设置启动窗体的大小和位置,使用到了ICSharpCode.Core.PropertyService类,该类将配置文件保存在"C:\Documents and Settings\michael\Application Data\michael's add-in test\myCfgParas.xml",其中[michael]是计算机名;[michael's add-in test]是应用程序名称,在程序启动时创建CoreStartup实例时指定;[myCfgParas.xml]由属性 CoreStartup.PropertiesName指定(详见后面Main()中的代码)。
Commands.cs
1//using
2namespace MainForm
3{
4 public class CmdBlack : AbstractMenuCommand
5 {
6 public override void Run()
7 {
8 FrmMain frm = (FrmMain)this.Owner;
9
10 StringBuilder sBuilder = new StringBuilder();
11 ArrayList alDatas = AddInTree.BuildItems("/michael/BlackText", null, true);
12 foreach (string str in alDatas)
13 sBuilder.AppendLine("suported types: " + str);
14
15 frm.DrawMsg(sBuilder.ToString(), Color.Black);
16 }
17 }
18
19 public class CmdExit : AbstractMenuCommand
20 {
21 public override void Run()
22 {
23 FrmMain frm = (FrmMain)this.Owner;
24 if (MessageBox.Show("Sure to exit?","Info:",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question) == DialogResult.Yes)
25 frm.Close();
26 }
27 }
28}
可以看到插件类必须实现ICommand接口或继承AbstractMenuCommand类,ICommand接口定义的Owner属性返回该对象的拥有者Object,在此例子中即FrmMain对象,CmdBlack类中通过((FrmMain)Owner).DrawMsg(...)向主窗体发出功能命令。
至此,只剩下对ICSharpCode.Core进行必要的初始化配置了(参见Demo中的Entry项目Program.cs中的static void Main()函数):
void Main
1LoggingService.Info("Application start");
2Assembly asm = Assembly.GetExecutingAssembly();
3FileUtility.ApplicationRootPath = Path.GetDirectoryName(asm.Location);
4ResourceService.RegisterNeutralStrings(new ResourceManager("Entry.StrImgRes", asm));
5ResourceService.RegisterNeutralImages(new ResourceManager("Entry.StrImgRes", asm));
6
7LoggingService.Info("Starting core services");
8CoreStartup coreStartup = new CoreStartup("michael's add-in test");
9coreStartup.PropertiesName = "myCfgParas";
10coreStartup.StartCoreServices();
11// 在指定文件夹中搜寻插件的配置文件
12coreStartup.AddAddInsFromDirectory(Path.Combine(FileUtility.ApplicationRootPath, "myAddIns"));
13// AddinManager 插件的属性:保存用户禁用的插件信息
14coreStartup.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml"));
15// AddinManager 插件的属性:保存用户安装的插件信息
16coreStartup.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"),
17 Path.Combine(PropertyService.ConfigDirectory, "AddIns"));
18coreStartup.RunInitialization();
19try
20{
21 LoggingService.Info("Running application");
22 Application.Run(MainForm.FrmMain.Instance);
23}catch{
24
注:
Demo 项目引用的AddinManager也是SharpCode.Core中的一个插件实现,查看AddinManager.Addin,可见其定义了菜单项、新界面(点击新菜单时Run()方法中定义弹出的新窗体)、新界面的上下文菜单,上下文菜单中使用配置菜单项何时可用……
Demo项目中扩展菜单的例子参见Demo中的ExtenalMenus工程中的Command.cs和ExternalMenu.addin,该项目实现了两个新的菜单项,并且实现了一个自定义的Doozer。
6、总结:
a, ICSharpCode.Core默认实现的Doozer
Class 根据配置文件的声明由System.Reflection创建出相关对象
FileFilter 创建出路径后缀名的过滤选项提供给OpenFileDialog或是SaveFileDialog使用
Include 向addin tree引进一个(使用item属性)或多个(使用path属性)子项
Icon 用以创建文件类型与图标间的关联
MenuItem 创建菜单项 type可为:Seperator, CheckBox, Item/Command, Menu, Builder
ToolBarItem 创建工具栏按钮荐 type可为:Seperator, CheckBox, Item, ComboBox, DropDownButton
b, 配置文件中引用预定义资源格式
${res:ResourceName} 引用ResourceService系统资源
${property:PropertyName} 引用PropertyService中的属性
${env:VariableName} 引用系统变量
${exe:ProperName} 引用整个程序集的属性
c, Condition
[略(有待进一步分析)]
7、相关资料:
《Dissecting a C# Application Inside SharpDevelop.pdf》
SharpDevelop源代码(\src\ 和 \samples\ICSharpCode.Core.Demo\)
http://www.sharpdevelop.com/OpenSource/SD/Default.aspx
http://www.codeproject.com/csharp/ICSharpCodeCore.asp
使用AddIn好处:
AddIn实现分析:
SharpDevelop重要概念
Demo代码分析
总结:
相关资料:
Demo下载
1、Demo运行界面:
程序初始运行界面如下:
添加插件界面如下:
添加插件后界面如下:
运行环境:VS2005
2、使用AddIn好处
方便扩展,可以看到SharpDevelop几乎是通过插接功能模块组装而成;核心可以不必实现自己的定义,方便地通过接口扩充功能;插件dll可以放在任意位置,对插件使用拷贝、粘贴式的部署。
许多应用程序也使用了一些插件机制,但大多数局限于特定的功能,如扩展菜单或新文件格式。SharpDevelop插件体系的目标是为应用程序提供简单易用而又强大的扩展点,allowing AddIns to extend nearly everything.
3、AddIn实现分析:
简单分析后,实现思路是这样的:定义一个接口ICommand,声明void DoCommand()方法,新增插件必须实现此接口;
单击菜单项或工具栏按钮时需要与主窗体交互,这可以通过在ICommand中定义属性MainForm或在void DoCommand(MainForm frm)中增加方法参数来传递主窗体的引用,这些实现起来倒也简单。
接下来的问题是如何通知应用程序新增加了插件呢,答案是使用xml配置文件,怎么组织这个配置文件的结构呢?这个问题其实成了实现插件功能的重点和难点,配置文件中希望说明新增插件的dll位置、类名、插接入主程序的菜单还是工具栏项、插接位置,或许还希望配置文件更容易被扩展?
这里(http: //www.codeproject.com/cs/library/Net_AddinProjFrmwork.asp)有一个结构不太好的配置文件定义形式(可能也是我们简单分析后会想到的定义方式,可以看出结构固定,且不易扩展),大家可以自行分析下:
sample.xml
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
现在来看看SharpDevelop的AddIn配置文件结构(参见Demo中的Entry.myAddins.Menus.addin):
Menus.addin
1
3 url = "http://www.cnblogs.com/michael-zhang/"
4 description = "基本插件"
5 addInManagerHidden = "true">
6
7
8
9
10
11
12
13
14
15
16
17
18
19
40
41
43 icon = "qq.face1"
44 class = "MainForm.CmdBlack"/>
45
46
48 icon = "CloseIcon"
49 class = "MainForm.CmdExit"/>
50
51
后面的形如
注:
addin配置文件中的 label = "${res:Demo.Menu.File}", icon = "qq.face1" 等属性值是指向资源文件的引用,资源文件见Entry项目的StrImgRes.resx
4、SharpDevelop插件树中的重要概念
Condon: 代表
Doozer: 代表Condon节点的更具体的实例,如MenuItemDoozer, ToolBarItemDoozer, FileFilterDoozer, IncludeDoozer, FileFilterDoozer等,用以创建具体的object对象,可以扩展编写自定义的Doozer。
5、Demo项目代码分析
至此,我们大概能猜到SharpDevelop中的插件机制是怎样的,下面就结合Demo的分析来体验一下SharpDevelop的插件功能:
MainForm.FrmMain.cs中使用单件模式获取此类,关键代码如下:
FrmMain.cs
1using ICSharpCode.Core;
2
3// 变量声明
4const string _BoundProperty = "FormBounds";
5Label _lblMsg;
6MenuStrip _menuStrip;
7ToolStrip _toolStrip;
8//
9void IniFrm()
10{
11 // 设置窗体位置
12 Rectangle rect = PropertyService.Get
13 this.StartPosition = FormStartPosition.Manual;
14 this.Bounds = rect;
15 this.FormClosing += delegate
16 {
17 // 设置用户属性信息
18 PropertyService.Set
19 };
20
21 _lblMsg = new Label();
22 _lblMsg.Dock = DockStyle.Fill;
23 _lblMsg.Font = new Font("Arial", 16, FontStyle.Bold);
24 _lblMsg.Text = "App loaded!";
25 this.Controls.Add(_lblMsg);
26
27 _toolStrip = ToolbarService.CreateToolStrip(this, "/michael/myToolbar");
28 this.Controls.Add(_toolStrip);
29
30 _menuStrip = new MenuStrip();
31 MenuService.AddItemsToMenu(_menuStrip.Items, this, "/michael/myMenus");
32 this.Controls.Add(_menuStrip);
33}
34public void DrawMsg(string msg,Color color)
35{
36 _lblMsg.Text = msg;
37 _lblMsg.ForeColor = color;
38}
主窗体的类中声明了Label, MenuStrip, ToolStrip 分别用以显示文字、菜单、工具栏。菜单、工具栏对象的获取通过ICSharpCode.Core内置类仅用简单的两行代码实现。此类中公开的 DrawMsg(...)方法用以向扩展菜单、工具栏按钮等提供公开可调用的功能。创建菜单、工具栏的两个方法中的一个重要参数是路径参数(分别是 "/michael/myToolbar"和"/michael/myMenus"),在前面的配置文件代码中可以找到相关定义节,其中相关节点一个重要属性是class, 该属性指定了(菜单、工具栏按钮的)相关类,其实现代码如下(MainForm项目的Commands.cs):
注:
FrmMain 类的IniFrm()方法中前几行代码用以设置启动窗体的大小和位置,使用到了ICSharpCode.Core.PropertyService类,该类将配置文件保存在"C:\Documents and Settings\michael\Application Data\michael's add-in test\myCfgParas.xml",其中[michael]是计算机名;[michael's add-in test]是应用程序名称,在程序启动时创建CoreStartup实例时指定;[myCfgParas.xml]由属性 CoreStartup.PropertiesName指定(详见后面Main()中的代码)。
Commands.cs
1//using
2namespace MainForm
3{
4 public class CmdBlack : AbstractMenuCommand
5 {
6 public override void Run()
7 {
8 FrmMain frm = (FrmMain)this.Owner;
9
10 StringBuilder sBuilder = new StringBuilder();
11 ArrayList alDatas = AddInTree.BuildItems("/michael/BlackText", null, true);
12 foreach (string str in alDatas)
13 sBuilder.AppendLine("suported types: " + str);
14
15 frm.DrawMsg(sBuilder.ToString(), Color.Black);
16 }
17 }
18
19 public class CmdExit : AbstractMenuCommand
20 {
21 public override void Run()
22 {
23 FrmMain frm = (FrmMain)this.Owner;
24 if (MessageBox.Show("Sure to exit?","Info:",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question) == DialogResult.Yes)
25 frm.Close();
26 }
27 }
28}
可以看到插件类必须实现ICommand接口或继承AbstractMenuCommand类,ICommand接口定义的Owner属性返回该对象的拥有者Object,在此例子中即FrmMain对象,CmdBlack类中通过((FrmMain)Owner).DrawMsg(...)向主窗体发出功能命令。
至此,只剩下对ICSharpCode.Core进行必要的初始化配置了(参见Demo中的Entry项目Program.cs中的static void Main()函数):
void Main
1LoggingService.Info("Application start");
2Assembly asm = Assembly.GetExecutingAssembly();
3FileUtility.ApplicationRootPath = Path.GetDirectoryName(asm.Location);
4ResourceService.RegisterNeutralStrings(new ResourceManager("Entry.StrImgRes", asm));
5ResourceService.RegisterNeutralImages(new ResourceManager("Entry.StrImgRes", asm));
6
7LoggingService.Info("Starting core services");
8CoreStartup coreStartup = new CoreStartup("michael's add-in test");
9coreStartup.PropertiesName = "myCfgParas";
10coreStartup.StartCoreServices();
11// 在指定文件夹中搜寻插件的配置文件
12coreStartup.AddAddInsFromDirectory(Path.Combine(FileUtility.ApplicationRootPath, "myAddIns"));
13// AddinManager 插件的属性:保存用户禁用的插件信息
14coreStartup.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml"));
15// AddinManager 插件的属性:保存用户安装的插件信息
16coreStartup.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"),
17 Path.Combine(PropertyService.ConfigDirectory, "AddIns"));
18coreStartup.RunInitialization();
19try
20{
21 LoggingService.Info("Running application");
22 Application.Run(MainForm.FrmMain.Instance);
23}catch{
24
注:
Demo 项目引用的AddinManager也是SharpCode.Core中的一个插件实现,查看AddinManager.Addin,可见其定义了菜单项、新界面(点击新菜单时Run()方法中定义弹出的新窗体)、新界面的上下文菜单,上下文菜单中使用
Demo项目中扩展菜单的例子参见Demo中的ExtenalMenus工程中的Command.cs和ExternalMenu.addin,该项目实现了两个新的菜单项,并且实现了一个自定义的Doozer。
6、总结:
a, ICSharpCode.Core默认实现的Doozer
Class 根据配置文件的声明由System.Reflection创建出相关对象
FileFilter 创建出路径后缀名的过滤选项提供给OpenFileDialog或是SaveFileDialog使用
Include 向addin tree引进一个(使用item属性)或多个(使用path属性)子项
Icon 用以创建文件类型与图标间的关联
MenuItem 创建菜单项 type可为:Seperator, CheckBox, Item/Command, Menu, Builder
ToolBarItem 创建工具栏按钮荐 type可为:Seperator, CheckBox, Item, ComboBox, DropDownButton
b, 配置文件中引用预定义资源格式
${res:ResourceName} 引用ResourceService系统资源
${property:PropertyName} 引用PropertyService中的属性
${env:VariableName} 引用系统变量
${exe:ProperName} 引用整个程序集的属性
c, Condition
[略(有待进一步分析)]
7、相关资料:
《Dissecting a C# Application Inside SharpDevelop.pdf》
SharpDevelop源代码(\src\ 和 \samples\ICSharpCode.Core.Demo\)
http://www.sharpdevelop.com/OpenSource/SD/Default.aspx
http://www.codeproject.com/csharp/ICSharpCodeCore.asp
SharpDevelop浅析_1_AddInTree 使用ICSharpCode.Core创建插件支持的应用程序
SharpDevelop浅析_5_Windows Forms Designer 自己动手创建应用程序界面设计器
SharpDevelop浅析_2_User Interface 创建易扩展且功能模块松散耦合的应用程序 (转 study log)
使用图形编辑框架创建基于 Eclipse 的应用程序 [转]
使用Maven 2创建WebLogic Portal应用程序
使用 HTML 5 创建移动 Web 应用程序,第 2 部分: 使用 HTML 5 开启移动 Web 应用程序的本地存储
ASP.NET 2.0使用Web Part创建应用程序之一(共二) - 海东的技术资料 -...
使用 eclipse 插件来编辑、编译和调试应用程序
使用 eclipse 插件来编辑、编译和调试应用程序
我使用的Firefox插件
OpenCore:基于OSGi开发纯插件体系结构的WEB应用程序
简化管理面向服务的应用程序的创建
为脱机数据访问创建基于 Web 的应用程序
为脱机数据访问创建基于 Web 的应用程序
用 AJAX 构建支持实时验证的 Web 应用程序
使用 PHP 和 DHTML 设计 Web 2.0 应用程序,第 2 部分: 使用 JavaScript 创建 HTML 动态元素
使用 PHP 和 DHTML 设计 Web 2.0 应用程序,第 2 部分: 使用 JavaScript 创建 HTML 动态元素
VB创建多线程应用程序(二)
aix下core 文件的使用(转载) - IBM产品及AIX - IXPUB技术社区
使用应用程序资源
从创建一个应用程序到制作一个安装包的详细过程
用 RUP 创建易访问的应用程序(转与Rational Edge)
创建第一个简单的Silverlight应用程序 - Silverlight上海开发团队Bl...
Maven插件使用收集