前一段看了看Sharepdevlop的源代码。里边的插件树给了我写程序的启发。于是就想写一个自己的插件管理。
下边是我的程序贴图

主要做的是功能的动态加载。可以单独开发每个功能。只要将其类写在配置文件中即可。配置文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<class dll ="AddIn\EditAddin\EditMenu.dll">
<menuitem name ="editmenuitem" path ="" text="编辑" classname ="EditMenu.EditMenu" />
<menuitem name ="selectallmenuitem" path ="editmenuitem" text="全选" classname ="EditMenu.SelectAll" />
<menuitem name ="copymenuitem" path ="editmenuitem" text="复制" classname ="EditMenu.Copy" />
<menuitem name ="cutmenuitem" path ="editmenuitem" text="剪切" classname ="EditMenu.Cut" />
<menuitem name ="pastemenuitem" path ="editmenuitem" text="粘贴" classname ="EditMenu.Paste" />
</class>
这是编辑菜单的配置文件
name是对应的菜单内部名子。path对应的是要插入到那个菜单的下边,如果是空则为最上级菜单。text是程序中显示的名子,classname是该功能菜单所对应的类。
然后定义一个通一的结口。用以实现在主程序中的调用
using System;
using System.Collections.Generic;
using System.Text;

namespace MainCommand
{
public interface ICommand
{
void Run();
}
public interface IMenuCommand:ICommand
{
void CheckItem(object sender, EventArgs e);
}
public interface IMenuCheckCommand : IMenuCommand
{
bool Check
{
get;
set;
}
bool Endable
{
get;
set;
}
}
}
下边代码是加载插件。
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using System.Reflection;
using MainCommand;

namespace MenuManage
{
//和配置文件中的属性对应
public class AddInXmlMenuItem
{
/// <summary>
///
/// </summary>
public string menuname;
public string menutext;
public string menupath;
public string classname;
}
public class AddInXmlmenu
{
/// <summary>
/// 用来载入动态库
/// </summary>
Assembly loadedAssembly = null;
/// <summary>
/// 存存配置信息
/// </summary>
public List<AddInXmlMenuItem> AddInXmlList = new List<AddInXmlMenuItem>();
public List<IMenuCommand> MenuCommandList = new List<IMenuCommand>();
/// <summary>
/// 动态库的路径
/// </summary>
public string classdll;
/// <summary>
/// 装载配置文件
/// </summary>
/// <param name="xmlname"></param>
public void LoadAddInXml(string xmlname)
{
XmlDocument document = new XmlDocument();
document.XmlResolver = null;
document.Load(xmlname);
for (int i = 0; i < document.ChildNodes.Count; i++)
{
XmlNode firstnode = document.ChildNodes[i];
if (firstnode.Name.Equals("class"))
{
classdll = firstnode.Attributes["dll"].Value;

loadedAssembly = Assembly.LoadFrom(classdll);

for (int j = 0; j < firstnode.ChildNodes.Count; j++)
{
XmlNode menunode = firstnode.ChildNodes[j];
switch (menunode.Name)
{
case "menuitem":
{
AddInXmlMenuItem item = new AddInXmlMenuItem();
item.classname = menunode.Attributes["classname"].Value;
item.menuname = menunode.Attributes["name"].Value;
item.menupath = menunode.Attributes["path"].Value;
item.menutext = menunode.Attributes["text"].Value;

IMenuCommand command = loadedAssembly.CreateInstance(item.classname) as IMenuCommand;
AddInXmlList.Add(item);
MenuCommandList.Add(command);
}
break;
default:
break;
}
}
}
}
}
}
static class AddInClass
{
public static MenuStrip MenuObject;
static public List<AddInXmlmenu> AddInXml = new List<AddInXmlmenu>();
/// <summary>
/// 初始化插件
/// </summary>
static public void InitAddInClass()
{
//读取插件
string[] straddin = Directory.GetDirectories("AddIn");
for (int i = 0; i < straddin.Length; i++)
{
string pathstr = straddin[i];
string[] filename = Directory.GetFiles(pathstr);
for (int j = 0; j < filename.Length; j++)
{
string exte = Path.GetExtension(filename[j]);
if (exte.Equals(".AddIn"))
{
AddInXmlmenu tempxmlmenu = new AddInXmlmenu();
tempxmlmenu.LoadAddInXml(filename[j]);
if (tempxmlmenu.AddInXmlList.Count > 0)
{
AddInXml.Add(tempxmlmenu);
}
}
}
}
}
/// <summary>
/// 增加菜单
/// </summary>
static public void AddMenuItem()
{
for (int i = 0; i < AddInXml.Count; i++)
{
AddInXmlmenu itemmenu = AddInXml[i];
for (int j = 0; j < itemmenu.AddInXmlList.Count; j++)
{
AddInXmlMenuItem item = itemmenu.AddInXmlList[j];
ToolStripMenuItem toolitem = CreateMenuItem(item.menuname, item.menutext, item.menupath);
if (toolitem == null)
{
continue;
}
IMenuCommand command = itemmenu.MenuCommandList[j] as IMenuCommand;
command.Run();
toolitem.Click +=new EventHandler(command.CheckItem);
}
}
}
/// <summary>
/// 建立菜单项目
/// </summary>
/// <param name="name"></param>
/// <param name="text"></param>
/// <param name="menu"></param>
static private ToolStripMenuItem CreateMenuItem(string name, string text, string menu)
{
if (MenuObject != null)
{
ToolStripMenuItem item = new ToolStripMenuItem();
item.Name = name;
item.Text = text;
if (menu == "")
{
MenuObject.Items.Add(item);
}
else
{
ToolStripMenuItem parent = GetToolItem(menu);
if (parent != null)
{
parent.DropDownItems.Add(item);
}
}
return item;
}
return null;
}
/// <summary>
/// 得到要插入的菜单项
/// </summary>
/// <param name="itempath"></param>
/// <returns></returns>
static private ToolStripMenuItem GetToolItem(string itempath)
{

string[] word = itempath.Split('\\');
ToolStripMenuItem item = MenuObject.Items[word[0]] as ToolStripMenuItem;
if (item != null)
{
for (int i = 1; i < word.Length; i++)
{
if (word[i].Length > 0)
{
item = item.DropDownItems[word[i]] as ToolStripMenuItem;
}
}
}
else
{
return null;
}

return item;
}
}
}
以下是源代码地址:https://files.cnblogs.com/xtpgkxk/插件管理.rar
下边是我的程序贴图
主要做的是功能的动态加载。可以单独开发每个功能。只要将其类写在配置文件中即可。配置文件如下:








name是对应的菜单内部名子。path对应的是要插入到那个菜单的下边,如果是空则为最上级菜单。text是程序中显示的名子,classname是该功能菜单所对应的类。
然后定义一个通一的结口。用以实现在主程序中的调用





























下边代码是加载插件。



































































































































































































【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述