模块化程序.在主机中调用函数

本文关键字:调用 函数 主机 程序 模块化 | 更新日期: 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
}

我不认为这是应该的工作方式。我认为我应该能够通过接口和模块来填充。。。

评论?