2004年09月01日

 

 

       AddIn树是由一个提供其余应用程序所用功能的接口定义的。为了总览该结构所提供的功能,我们将介绍IAddInTree接口,它位于src\Main\Core\AddIns\IAddInTree.cs

       public interface IAddInTree

       {

              /// <summary>

              /// Returns the default condition factory. ICondition objects

              /// are created only with this factory during the tree

              /// construction process.

              /// </summary>

              ConditionFactory ConditionFactory {

                     get;

              }

 

              /// <summary>

              /// Returns the default codon factory. ICodon objects

              /// are created only with this factory during the tree

              /// construction process.

              /// </summary>

              CodonFactory CodonFactory {

                     get;

              }

 

              /// <summary>

              /// Returns a collection of all loaded add-ins.

              /// </summary>

              AddInCollection AddIns {

                     get;

              }

             

              /// <summary>

              /// Returns a TreeNode corresponding to <paramref name=”path”/>.

              /// </summary>

              /// <param name=”path”>

              /// The path.

              /// </param>

              /// <exception cref=”TreePathNotFoundException”>

              /// When the path <paramref name=”path”/> does not point to a codon

              /// in the tree.

              /// </exception>

              IAddInTreeNode GetTreeNode(string path);

             

              /// <summary>

              /// Inserts an AddIn into the AddInTree.

              /// </summary>

              void InsertAddIn(AddIn addIn);

 

              /// <summary>

              /// Removes an AddIn from the AddInTree.

              /// </summary>

              void RemoveAddIn(AddIn addIn);

             

              /// <summary>

              /// This method does load all codons and conditions in the given assembly.

              /// It will create builders for them which could be used by the factories

              /// to create the codon and condition objects.

              /// </summary>

              Assembly LoadAssembly(string assemblyFile);

       }

 

       首先,AddIn树包含ConditionFactorCodonFactory对象,这些工厂创建了AddIn树节点内容。下一个属性是AddIn属性。

       AddIns属性之后是GetTreeNode方法,该方法非常重要,是使用AddIn树插件唯一所需要的方法。其他方法和属性当前只内部的用于核心程序集。

       InserAddInRemoveAddIn方法可能用于IDE中实现插件管理器,但当前并为使用。了解IAddInTree接口的重要方法之后,让我们看一下插件文件的定义。

2004年08月30日

 

 

       与其它设计方法相比,AddIn树有不少优点:

l         可以通过其他插件扩展以有插件。但这样做的主要问题是:其他插件执行动作时必须通知以有的插件。

l         在者,包含可执行代码的assembly文件不必驻留在一个目录中。开发人员可以将它们存储在任何位置,插件系统将管理文件加载。这就使实现插件的“复制和删除”部署变得非常容易。只须将包含XML定义和所需要程序集的插件文件夹复制到SharpDevelop AddIn 文件夹,就奏效了。删除目录,插件就会被取出!注意,.NET标准将把所有程序集都放在一个bin目录中。

l         使用上述方法时,查检不必实现自己的插件结构,因为所有插件都基于一个系统—AddIn数。通过一个窄接口,我们可以定义任何功能

 

src\Main\StartUp\SharpDevelopMain.cs文件中,有一个运行所有动作的方法:

       public class SharpDevelopMain

       {

              static string[] commandLineArgs = null;

             

              public static string[] CommandLineArgs {

                     get {

                            return commandLineArgs;

                     }

              }

             

              static void ShowErrorBox(object sender, ThreadExceptionEventArgs eargs)

              {

                     DialogResult result = new ExceptionBox(eargs.Exception).ShowDialog();

 

                     switch (result) {

                            case DialogResult.Ignore:

                                   break;

                            case DialogResult.Abort:

                                   Application.Exit();

                                   break;

                            case DialogResult.Yes:

                                   break;

                     }

              }

             

              /// <summary>

              /// Starts the core of SharpDevelop.

              /// </summary>

              [STAThread()]

              public static void Main(string[] args)

              {

                     commandLineArgs = args;

                     bool noLogo = false;

                    

                     SplashScreenForm.SetCommandLineArgs(args);

                    

                     foreach (string parameter in SplashScreenForm.GetParameterList()) {

                            switch (parameter.ToUpper()) {

                                   case “NOLOGO”:

                                          noLogo = true;

                                          break;

                            }

                     }

                    

                     if (!noLogo) {

                            SplashScreenForm.SplashScreen.Show();

                     }

                     Application.ThreadException += new ThreadExceptionEventHandler(ShowErrorBox);

                    

                     bool ignoreDefaultPath = false;

                     string [] addInDirs = ICSharpCode.SharpDevelop.AddInSettingsHandler.GetAddInDirectories(out ignoreDefaultPath);

                     AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath);

                    

                     ArrayList commands = null;

                     try {

                            ServiceManager.Services.AddService(new MessageService());

                            ServiceManager.Services.AddService(new ResourceService());

                            ServiceManager.Services.AddService(new IconService());

                            ServiceManager.Services.InitializeServicesSubsystem(“/Workspace/Services”);

                    

                            commands = AddInTreeSingleton.AddInTree.GetTreeNode(“/Workspace/Autostart”).BuildChildItems(null);

                            for (int i = 0; i < commands.Count – 1; ++i) {

                                   ((ICommand)commands[i]).Run();

                            }

                     } catch (XmlException e) {

                            MessageBox.Show(“Could not load XML :” + Environment.NewLine + e.Message);

                            return;

                     } catch (Exception e) {

                            MessageBox.Show(“Loading error, please reinstall :”  + Environment.NewLine + e.ToString());

                            return;

                     } finally {

                            if (SplashScreenForm.SplashScreen != null) {

                                   SplashScreenForm.SplashScreen.Close();

                            }

                     }

                    

                     try {

                            // run the last autostart command, this must be the workbench starting command

                            if (commands.Count > 0) {

                                   ((ICommand)commands[commands.Count - 1]).Run();

                            }

                     } finally {

                            // unloading services

                            ServiceManager.Services.UnloadAllServices();

                     }

              }

       }

 

首先,Main方法初始化启动画面,这不太重要,但当我们作实际工作时,如生成AddIn树,用户至少会看到一些内容。

try…catch块非常重要。为AddIn树创建一个调用,以获取数节点,然后他会从该节点生成所有子项目。

此后,for语句将这些生成的子项目强制转换为ICommand 接口,并调用 Run 方法最后一个除外。

try…catch快之后,启动最后一个命令。我们将分别启动,以确保启动最后一个命令时关闭启动画面。最后一个命令激活IDE的工作台窗体,并运行消息循环。

按照SharpDevelop不再核心嵌入任何GUI层,这就是为其他工具箱的进一步使用提供了良好的扩展性。在应用程序实际需要时才会实现GUI层。

只需要在树中放入其他Run命令,就可以在树创建一个完全不同的应用程序。该引用程序可受益AddIn树。

返回最后一个Run命令时,就认为应用程序消息循环已经结束,于是通过服务卸载进行清理。

 
作者:Eric

本文介绍SharpDevelop的基础结构。与大多数应用程序相同,SharpDevelop的核心是可执行的;又与大多数应用程序不同,他只是提供了包含其它主要任务(加载和生成AddIn树)在内的几个基本服务。 Add-ins也成为Plug-ins,这里我们还是用Add-ins这个术语。

本文将介绍AddIn树的结构和实现,并讲述AddIn的对象创建机制。还将介绍SharpDevelop是如何管理属性持久性的。

核心基础结构与其余代码是相分离的,您可以在scr\SharpDevelop\Core目录下找到它。全部插件系统位于子文件夹AddIns下的该文件夹中。

1、  AddIn

AddIn树是一个简单的树数据结构。SharpDevelop的每一个实例只有一个AddIn树,所以我们通过singleton设计模式来实现他。

XML文件和XML引用的DLL集定义了一个插件。DLL提供了代码,XML定义了将其插入到AddIn树的方式和位置。

AddIn树是一种“将他们全部邦定的树”,插件是AddIn树的节点,路经的作用是构造树,因此不是真正的节点。IDE根据这些节点的定义内容更改行为。节点的路经结构好像是一个文件系统,如果访问SubNode2,必须将位置指定为/Path1/SubPat1/Node1/SubNode2。这里,Node1似乎是一个路径(以后将介绍路径和节点的区别)。可以说,节点是包含行为定义的路径。

定义特定路径的插件也着手定义可插入到旗下的节点的接口,如图:

 

    在选项面板左侧,我们可以从树试图中看到AddIn树节点。文件夹表示空节点,其他为包含文件夹图标的树树突节点是包含面板的节点。要添加新面板,插件必须将正确节点插入到路径,对话框将显示他们。在SharpDevelop中,所有可见元素都有节点定义;大多数不可见元素,如文本编辑器中的键盘命令cursor keys,在插件树中也被作为节点实现。