模块化程序.在主机中调用函数
本文关键字:调用 函数 主机 程序 模块化 | 更新日期: 2023-09-27 18:29:51
我使用构建了一个模块化程序
http://www.codeproject.com/Articles/258681/Windows-Forms-Modular-App-using-MEF作为基础,我有几个模块在工作。
这是一个MDI Windows窗体应用程序,我需要回叫主机模块来获取一些东西。
a) MDI主机窗口的位置信息
b) 写入主机窗口中的状态栏。
我已经设法编译了应用程序,但当我调用主机函数时,它总是给我一个空异常
我确实看过使用C#的MEF,我如何从插件中调用主机上的方法?
这就是我的线路
public Exec.Core.Interfaces.IHost Host;
但是主机总是空的,所以我在尝试访问作为主机的MDIForm的成员时会遇到异常。
即使我做公共Exec.Core.Interfaces.IHost主机{get;set;}
这就是主机。
NameSpace Exec
{
[Export(typeof(Exec.Core.Interfaces.IHost))]
// MDIForm is the host.
public partial class MDIForm : Form, Exec.Core.Interfaces.IHost
{
///other stuff not related to the problem
// defined in public interface IHost
public Point myLocation()
{
return this.Location; // need the window location
}
// defined in public interface IHost
public IHost GetHost()
{ // is this what GetHost Should Return? Not sure
return this;
}
// defined in public interface IHost
public void SendMessage(string message)
{
SetStatusBar(message); // print a message to MDIForm status bar
}
}
}
然后是IHosts.cs
namespace Exec.Core.Interfaces
{
public interface IHost
{
IHost GetHost();
void SendMessage(string message);
Point myLocation();
// MDIForm GetThis( ); /* this gives error. Can't resolve MDIForm
I don't know why and can't resolve.*/
}
}
这是我试图从主机获取内容的模块之一
namespace Exec.Modules.Tasks
{
[Export]
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
// unfortunately Host == NULL at this point
private void SendMessage (string message)
{
try
{
Host.SendMessage(message); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private IHost WhichHost()
{
try
{ /// not really sure what will be returned here
return GetHost();<Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private Point Location()
{
try
{
return mylocation(); <Throws System.NullReferenceException
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
最后,这就是我如何将所有对象放在ModuleHandler.cs中这几乎是从上面的代码项目中截取的,将一些方法调用分离为两部分,这样我就可以理解它为什么会消亡。
namespace Exec.Core
{
[Export(typeof(IModuleHandler))]
public class ModuleHandler : IDisposable, IModuleHandler
{
[ImportMany(typeof(IModule), AllowRecomposition = true)]
// The ModuleList will be filled with the imported modules
public List<Lazy<IModule, IModuleAttribute>> ModuleList
{ get; set; }
[ImportMany(typeof(IMenu), AllowRecomposition = true)]
// The MenuList will be filled with the imported Menus
public List<Lazy<IMenu, IModuleAttribute>> MenuList { get; set; }
[Import(typeof(IHost))]
// The imported host form
public IHost Host { get; set; }
AggregateCatalog catalog = new AggregateCatalog();
public void InitializeModules()
{
// Create a new instance of ModuleList
ModuleList = new List<Lazy<IModule, IModuleAttribute>>();
// Create a new instance of MenuList
MenuList = new List<Lazy<IMenu, IModuleAttribute>>();
// Foreach path in the main app App.Config
foreach (var s in ConfigurationManager.AppSettings.AllKeys)
{
if (s.StartsWith("Path"))
{
// Create a new DirectoryCatalog with the path loaded from the App.Config
DirectoryCatalog cataloglist = new DirectoryCatalog(ConfigurationManager.AppSettings[s], "jobexe*.dll");
catalog.Catalogs.Add(cataloglist);
}
}
// Create a new catalog from the main app, to get the Host
catalog.Catalogs.Add( new AssemblyCatalog(System.Reflection.Assembly.GetCallingAssembly()));
// Create a new catalog from the ModularWinApp.Core
DirectoryCatalog catalogExecAssembly = new DirectoryCatalog( System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location ), "exe*.dll");
catalog.Catalogs.Add(catalogExecAssembly);
// Create the CompositionContainer
CompositionContainer cc = new CompositionContainer(catalog);
try
{
cc.ComposeParts(this);
}
catch (ReflectionTypeLoadException e)
{ MessageBox.Show(e.ToString()); }
catch (ChangeRejectedException e)
{ MessageBox.Show(e.ToString()); }
}
}
}
因此,模块独立工作,但无法调用回主机。想知道我做错了什么。
提前感谢的任何帮助
最后一件事可能与这个问题有关。
这是启动程序的代码
public static ModuleHandler _modHandler = new ModuleHandler();
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
// this goes straight to class MDIForm() constructor
Application.Run(_modHandler.Host as Form);
}
Colin
手动实例化ModuleHandler
,然后调用InitializeModules
,在那里创建一个目录并将其传递给一个新的组合容器。然后,该容器用于通过以下行满足特定ModuleHandler
实例的所有导入:
cc.ComposeParts(this);
这个命令告诉MEF查找Import
属性,并用用相应的Export
属性修饰的类的实例填充修饰的属性。
您缺少的是填充frmTasks
对象的类似调用。因此,不满足以下Import
,并且属性为null
:
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
你有几个选择,其中我会研究以下两个:
修改
IModule
接口,以便可以显式地将IHost
传递给模块。然后,在InitializeModules
中,在调用ComposeParts
之后,对组成的模块进行迭代,并将主机实例传递给它们。这说明了通过IModule
接口设置Host
属性。您也可以通过将MEF导入的属性放在IModule
接口中并为每个模块实例调用ComposeParts
来坚持它。通过ServiceLocator公开容器,并从模块中获取
IModuleHandler
实例以访问Host
属性。
我有一个答案,我只是觉得不对。关于我的问题,我编辑了它并添加了主程序,但我没有添加它的类。
看起来像
namespace Exec
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
//Create a new instance of ModuleHandler. Only one must exist.
public static ModuleHandler _modHandler = new ModuleHandler();
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Initialize the modules. Now the modules will be loaded.
_modHandler.InitializeModules();
Application.Run(_modHandler.Host as Form);
}
}
}
我正在调试,发现在_modHandler.InitializeModules();
中
IHost主机已设置,它是的一部分
public static ModuleHandler _modHandler = new ModuleHandler();
这里的一切都是静态的,但无法访问。所以我把类签名改为public,使其成为全局的(我知道的脏话)
public static class Program
然后在中
namespace Exec.Modules.Tasks
在Load_Form事件中,我添加了一行初始化Host。
public partial class frmTasks : Form
{
[Import(typeof (Exec.Core.Interfaces.IHost))]
public Exec.Core.Interfaces.IHost Host;
private void Load_Form(object sender, EventArgs e)
{
Host = Program._modHandler.Host.GetHost; << added this to initialize host
other stuff....
}
other stuff that now works
}
我不认为这是应该的工作方式。我认为我应该能够通过接口和模块来填充。。。
评论?