C# 插件式开发示例
本文介绍.net开发中利用反射进行插件式开发的示例。
例子很简单,如下图所示的form中有一个picturebox,通过插件来对picturebox的Image进行编辑。
所有的插件必须实现主程序定义的接口,主程序相当于一个框架,具体的功能实现则由客户提供的插件完成,下面是解决方案的框架:
项目IPlug定义插件接口。DrawRectPlug和DrawTextPlug分别为两个具体的插件。
下面是我们定义接口
using System; using System.Drawing; using CommonSDK; namespace IPulg { public interface IPlug { /// <summary> /// 发布事件 /// </summary> event EventHandler<EventArgs<Image>> Handled; /// <summary> /// 插件按钮图标 /// </summary> /// <returns></returns> Bitmap GetToolIcon(); /// <summary> /// 处理图像,结果通过事件发布 /// </summary> /// <param name="img"></param> /// <param name="arg"></param> void DoHandlImage(Bitmap img, object arg); } }
STP 1 完成主界面加载插件的框架
我们规定插件的存放地址为bin/Debug/plugs目录下,因此我们通过System.IO.Directory.GetFiles方法找到该目录下的所有插件,通过反射生成插件的实例。
为了避免手工将插件复制到bin/Debug/plugs文件夹下,在DrawRectPlug和DrawTextPlug两个项目的生成事件中加下以下命令:
copy /V "$(TargetDir)$(TargetName).dll" "$(TargetDir)..\..\..\WindowsFormsExtents\bin\Debug\plugs"
以下是加载插件的核心代码
private void Form1_Load(object sender, EventArgs e) { string[] plugDlls = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath + @"\plugs", "*.dll"); foreach (string dll in plugDlls) { Assembly a = Assembly.LoadFrom(dll); System.Type[] types = a.GetTypes(); foreach (System.Type type in types) { System.Type[] interfaces = type.GetInterfaces(); if (type.GetInterface("IPlug") != null) { //IPulg.IPlug p = Activator.CreateInstance(type) as IPulg.IPlug; //Bitmap img = p.GetToolIcon(); //System.Windows.Forms.ToolStripButton toolItem = new ToolStripButton(img); //toolItem.Click += (c, e) => //{ // pictureBox1.Image = p.DoHandlImage((Bitmap)pictureBox1.Image, null); //}; //toolStrip1.Items.Add(toolItem); IPulg.IPlug plug = Activator.CreateInstance(type) as IPulg.IPlug; plug.Handled += new EventHandler<CommonSDK.EventArgs<Image>>(p_Handled); Bitmap img = plug.GetToolIcon(); System.Windows.Forms.ToolStripButton toolItem = new ToolStripButton(img); toolItem.Click += new EventHandler(toolItem_Click); toolItem.Tag = plug; toolStrip1.Items.Add(toolItem); } } } }
STP2、开发插件
1、DrawRectPlug
这个插件的功能是在图片上填充一个黑色的矩形框,矩形框的位置已被程序写死。为了能够被主程序正确加载,DrawRectPlug 需要实现Iplug接口。
public class DrawRectPlug : IPulg.IPlug { public event EventHandler<EventArgs<Image>> Handled; public Bitmap GetToolIcon() { return Properties.Resources.Screenshot; } public void DoHandlImage(Bitmap img, object arg) { using (Graphics g = Graphics.FromImage(img)) { g.FillRectangle(Brushes.Black, new Rectangle(0, 0, 100, 100)); Handled(this, new EventArgs<Image>(img)); } } }
2、DrawTextPlug插件略为复杂一点,它的功能是在图片上打印一段自定义的字符串,而允许用户指定其字体及大小
public class DrawTextPlug:IPulg.IPlug { public event EventHandler<EventArgs<Image>> Handled; public Bitmap GetToolIcon() { return Properties.Resources.Writing; } public void DoHandlImage(Bitmap img, object arg) { using (TextInputFrm frm = new TextInputFrm()) { frm.ShowDialog(); using (Graphics g = Graphics.FromImage(img)) { g.DrawString(frm.textBox1.Text, frm.fontDialog1.Font, Brushes.AliceBlue, 10, 10); if (Handled != null) Handled(this, new EventArgs<Image>(img)); } } } }
程序运行效果图