如何使用C#中的插件操作宿主应用程序?

时间:2013-04-10 09:57:19

标签: c# winforms plugins

我创建了一个可以托管插件的简单应用程序 如果插件提供依赖服务,那就没问题,但是当涉及到创建一个操纵主机本身的插件时(例如更改其BackColor,向其TextBox添加文本等)我似乎无法找到解决方案!
因为我尝试的每一种方法都不会起作用,因为它似乎是循环依赖 首先,我尝试在我的主机应用程序中创建一些公共SettersGetters,当我尝试将其添加为我IpluginInterface的引用时,它表示由于您不能循环依赖,
我尝试了一个中产阶级来实现主机应用程序的setter和getter,我再次面临同样的错误 我该怎么做才能避免此错误并操纵主机应用程序?

1 个答案:

答案 0 :(得分:2)

创建一个名为“Interfaces”的第三个项目,然后将接口放在那里的主应用程序中。当您插入插件时,通过该接口传入对主应用程序的引用。这可以防止循环引用。

主项目和插件都可以引用“接口”项目。

编辑:这是一个完整的代码示例。现在,当然,为了简单起见,我已将所有内容放在一个文件中,但我添加了关于每个部分通常驻留位置的注释。您提到的参数是插件不知道的类型。在这种情况下,只需在interfaces项目中添加一个新接口,并使该参数从该接口派生。

要运行此操作,请创建一个winforms项目并将该批次粘贴到新类中。然后删除旧表单和Program.cs文件。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    // This is the program start. Probably the place that would have loaded the plug ins.
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }

    //Form goes in project one and has a reference to Interfaces.
    public class MainForm : Form, IMainForm
    {
        private TextBox _textBox;
        private IPlugIn _thePlugIn;
        private Button _aButton;

        public MainForm()
        {
            InitializeComponent();
            _thePlugIn = ObtainPlugInsThroughMagic();
        }

        private IPlugIn ObtainPlugInsThroughMagic()
        {
            // So this would usually go off and load some DLLs and then instantiate the IPlugIn objects
            // We're cheating.
            var plugin = new MyPlugIn();
            plugin.Initialise(this);
            return plugin;
        }

        public void SetTextBoxValueFromPlugIn(string newText)
        {
            _textBox.Text = newText;
        }

        private void InitializeComponent()
        {
            _textBox = new TextBox();
            _aButton = new Button();
            SuspendLayout();

            _aButton.Location = new Point(20, 50);
            _aButton.Size = new Size(100, 25);
            _aButton.TabIndex = 1;
            _aButton.Click += AButtonClick;
            _aButton.Text = "Fire plug in";
            _textBox.Location = new Point(20, 10);            
            _textBox.Size = new Size(260, 20);
            _textBox.TabIndex = 0;

            AutoScaleDimensions = new SizeF(6F, 13F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(300, 100);
            Controls.Add(_textBox);
            Controls.Add(_aButton);
            Text = "Main form";
            ResumeLayout(false);
            PerformLayout();
        }

        private void AButtonClick(object sender, System.EventArgs e)
        {
            _thePlugIn.MakePlugInDoItsStuff();
        }
    }

    #region interfaces go in the new Interfaces project.

    public interface IMainForm
    {
        void SetTextBoxValueFromPlugIn(string newText);
    }

    public interface IPlugIn
    {
        void Initialise(IMainForm mainForm);
        void MakePlugInDoItsStuff();
    }

    #endregion

    // The plug in goes in the plug in project and has a reference to Interfaces.

    public class MyPlugIn : IPlugIn
    {
        public IMainForm MainForm { get; private set; }

        public void Initialise(IMainForm mainForm)
        {
            MainForm = mainForm;
        }

        public void MakePlugInDoItsStuff()
        {
            MainForm.SetTextBoxValueFromPlugIn("Text set from plug in");
        }
    }
}