以下例子实现界面和数据操作的分离,界面成为一个dll,数据操作部分成为一个dll。
先上一个框图:
从上面的框图可以看出整体上需要:三个接口
下面是代码:
(1)建立第一个项目(以便形成dll),名称为:PluginKernel,此项目里面只需定义三个接口,为了层次分明,这三个接口分在两个.cs文件中。
先在IControl.cs(或IApp)文件中定义两个接口:
namespace CSPluginKernel
{
public interface IApplicationObject //应用程序主界面接口
{
void SetDelegate( EventHandler target ); //传递一个委托,即函数指针作为形参,这个委托会保存在主界面对象的appEvent成员中
IDocumentObject GetActivatedDocuments(); // 获取当前使用的文档对象
}
public interface IDocumentObject //文档对象(文本框)接口
{
string SetText { get; set; }
Color SelectionColor { get; set; }
Font SelectionFont { get; set; }
}
}
然后IPlugin.cs文件中定义一个插件接口:
namespace CSPluginKernel {
public interface IPlugin
{
ConnectionResult Connect( IApplicationObject app ); //插件注册函数
void OnDestory();
void OnLoad(); //插件加载
void Run(); //运行插件
}
}
(2)建立第二个项目,名称为:MyPlugin1,此项目就包含一个具体插件类。
建立MyPlugin1.cs文件,在此文件中添加如下代码:
namespace MyPlugin1
{
public class MyPlugin1 : IPlugin
{
//成员变量
private IApplicationObject _App;
private IDocumentObject _CurDoc;
//函数
public MyPlugin1() { }
public ConnectionResult Connect( IApplicationObject app ) //注册,只用到_App
{
_App = app; //注册时保存住主界面对象_App
_App.SetDelegate(new EventHandler( this.ActiveDocumentChanged ) ); //注册时让主界面的事件appEvent保存住插件的函数指针
return ConnectionResult.Connection_Success; //返回连接成功字符串,通知注册成功
}
private void ActiveDocumentChanged( object sender , EventArgs e )
{
//比如在主界面调整了当前激活文本框,要通知给插件,使插件把数据显示在主界面当前激活的文本框中
_CurDoc = _App.GetActivedDocument();
}
public void Run()
{
//运算产生一些数据字符串“我的数据” ,具体代码略。
......
_CurDoc.SetText(”我的数据" ); //从而更新了数据并在主界面中显示
}
public void OnLoad() //初始化工作,用到_CruDoc有关
{
_CurDoc = _App.GetActivedDocument(); //插件加载时,保存住当前激活的文本框,下面还可以对文本框做一些初始化工作,比如设置文本框背景色
...... //其它初始化工作
}
public void OnDestory() { } //插件销毁的工作
} //类定义结束
} //命名空间结束
(3)建立第3个项目,名称为:App,此项目包含主界面
namespace App
{
public class frmMain:System.Windows.Forms.Form ,CSPluginKernel.IApplicationObject
{
//成员变量
private ArrayList plugins = new ArrayList(); //插件列表
TextBox txtBox1; //此TextBox继承与IDocumentObject接口,两个textbox只有一个是激活状态的
TextBox txtBox2; //此TextBox继承与IDocumentObject接口
private EventHandler[] appEvent; //事件数组,保存多个插件的函数指针,如果只有一个插件,就不需要数组了
//函数
private void LoadAllPlugins() //加载所有插件
{
Assembly tmp = Assembly.LoadFile( file );
Type[] types = tmp.GetTypes();
foreach( Type t in types )
{
plugins.Add( tmp.CreateInstance( t.FullName ) ); //用到反射技术,具体就不说了,省略了一些代码
}
foreach( IPlugin pi in plugins ) //注册并初始化每个插件
{
if( pi.Connect( (IApplicationObject)this ) == ConnectionResult.Connection_Success ) {
pi.OnLoad();
}
}
private void RunPlugin(int index) //运行插件,比如单击某个按钮,运行对应的插件
{
((IPlugin)plugins[index]).Run(); //省略了一些代码,具体选择哪个插件运行就不多说了
}
public void SetDelegate(EventHandler target ) //保存住插件中的函数指针
{
this.appEvent[index]=target; //具体index为多少就省略了,index也可以为插件名,则更方便
}
public IDocumentObject ChangeActivedDocument(int index) //改变当前激活的文本框,比如单击某个按钮时发生
{
this.appEvent[index](); //通知对应的插件主界面更改了当前文本框,具体index为多少就省略了。
}
private void frmMain_Load(object sender, EventArgs e) //界面显示时,加载所有插件
{
this.LoadAllPlugins();
}
}
}