1

I'm working on an application that supports various plugins (well, that's planned at least). And I'd love to have it beautiful.

So I want to let the plugin developer send a big control (like a panel or other containers) to my host application and have the user setup their settings for the plugin in the application.

That would take the plugin-developer's effort to somehow implement a settings-panel that runs by in an own window.

Thing is, I'm not sure how to do that. I can pass variables to my host application but as soon as I try to add the control to my container panel, I get a RemoteException, telling me that the field 'parent' on type 'System.Windows.Forms.Control' can't be found.

I tried to add the plugin-control that way:

panel.Controls.Add(pluginControl);

If I try it the other way around:

pluginControl.Parent = panel;

I get a SerializationException because the class System.Windows.Forms.Control isn't marked Serializable.

Maybe some person ran into the same thing and can help me. Let me know if you need more information!

Edit: Have a look on my current implementation: https://dl.dropboxusercontent.com/u/62845853/Random%20crap/NotModified_SamplePluginSystem.zip

Mogsdad
  • 44,709
  • 21
  • 151
  • 275
zokkker13
  • 161
  • 10

1 Answers1

1

I tried something which you can adorn to your needs:

First i created a PluginBase class and the proper EventArgs in a ClassLibrary:

 public abstract class PluginBase
{
    public abstract void Initialize();

    protected void showControl(UserControl control)
    {
        ShowControl(this, new ControlToBeShownEventArgs() { TheControl = control });
    }

    public event EventHandler<ControlToBeShownEventArgs> ShowControl = delegate { };
}

public class ControlToBeShownEventArgs : EventArgs
{
    public UserControl TheControl { get; set; }
}

This library is referenced by every Plugin and by the host application. The Plugin is in turn also a Class Library (build path set to the one of the host) inside i made a plugin inheriting this base type:

class SomePlugin : PluginBase
{
    public override void Initialize()
    {
        showControl(new UserControl1());
    }
}

The UserControl1 is the Control to be shown.

Done that, I next added the following code to the main window of the host:

    List<PluginBase> plugins = new List<PluginBase>();

    private void Form1_Load(object sender, EventArgs e) //Hook in the event too
    {
        DirectoryInfo dir = (new FileInfo(Assembly.GetExecutingAssembly().Location)).Directory;
        foreach (var item in dir.GetFiles())
        {
            if (item.Name.Contains("Plugin") && item.Name.EndsWith(".dll"))
            {
                Assembly ass = Assembly.LoadFile(item.FullName);
                foreach (Type type in ass.GetTypes().Where(t => t.BaseType.Name == "PluginBase"))
                {
                    PluginBase pibase = (PluginBase)Activator.CreateInstance(type,false);
                    plugins.Add(pibase);
                }

            }
        }
        foreach (var item in plugins)
        {
            item.ShowControl += item_ShowControl;
            item.Initialize();
        }

    }

    void item_ShowControl(object sender, ControlToBeShownEventArgs e)
    {
        this.Controls.Add(e.TheControl);
    }
Florian Schmidinger
  • 4,682
  • 2
  • 16
  • 28
  • 1
    Dont forget to build the plugin too or set a build order dependency – Florian Schmidinger Jan 27 '15 at 14:47
  • Tried to implement your suggestions. Turns out it ends in a SerializationException. I can't have a baseclass as I have to inherit from MarshalByRefObject so I tried to put your changes into the interface and the plugin. Example attached: https://dl.dropboxusercontent.com/u/62845853/Random%20crap/SamplePluginSystem.zip – zokkker13 Jan 27 '15 at 15:20
  • Difference is you build up an appdomain for each plugin. Do you have to do this with your requirements? – Florian Schmidinger Jan 27 '15 at 15:42
  • 1
    The only way to communicate between appdomains is through serializing and deserializing data. thats why you get this exception – Florian Schmidinger Jan 27 '15 at 15:48
  • 1
    See this article too: http://stackoverflow.com/questions/9127253/why-are-system-windows-forms-control-not-marked-as-serializable – Florian Schmidinger Jan 27 '15 at 16:00
  • What you could do is seperate UI from PluginLogic. Both have a common guid. Load the UI layer in the host domain as u see above, and put the logic in your appdomain the way you did before. sending a serializable object and the guid via the event. (EventArgs have to be serialzeable too) – Florian Schmidinger Jan 27 '15 at 16:17
  • I need the separate AppDomains as I want to remove/ update Plugins when updates are available or the user wants to remove a plugin. Not sure if it's possible to unload Plugins on-the-fly without relaunching the Host-Application. – zokkker13 Jan 27 '15 at 16:27
  • Thats definatly not possible. Loaded Assemblys stay loaded. – Florian Schmidinger Jan 27 '15 at 16:28
  • Too bad it's not an easy solution. – zokkker13 Jan 27 '15 at 16:30
  • Never did a plugin-based application before. But I really hate to restart applications just to add or remove plugins (like Firefox). Pretty sure ther users wouldn't mind though.. – zokkker13 Jan 27 '15 at 16:32
  • ever considered using wpf instead of winforms? – Florian Schmidinger Jan 27 '15 at 16:32
  • Didn't work with WPF deeply enough to satisfy my needs (probably a devil's loop I guess). What's possible with WPF that isn't possible with WinForms? – zokkker13 Jan 27 '15 at 16:34
  • Im not 100% sure about that so dont kill me but i think xaml can be serialized/deserialized – Florian Schmidinger Jan 27 '15 at 16:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/69678/discussion-between-zokkker13-and-florian-schmidinger). – zokkker13 Jan 27 '15 at 16:36
  • I was finally able to test a WPF Usercontrol to be imported into a WinForms host application. Turns out that serialization still throws an exception. Guess I'm lost :( – zokkker13 Jan 31 '15 at 23:13
  • Did you check the example i posted? – Florian Schmidinger Feb 01 '15 at 09:46