Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Implementing Plugin Architecture in WPF Without External Tools

Tech 2

This implementation demonstrates loading and executing a WPF application as a plugin with in a host application, using only native .NET capabilities.

The solution involves three projects: AbstractionLayer for defining interfaces, WPFIPluginDemo as the main application, and WpfPlugin3 as the loadable plugin module.

The AbstractionLayer project defines the IPlugin interface:

using System;

namespace AbstractionLayer
{
    public interface IPlugin
    {
        void Initialize();
    }
}

The main application's MainWindow.xaml inculdes two buttons for discovering and displaying plugins:

<Window x:Class="WPFIPluginDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <Button x:Name="btnSearchPlugins" Content="Discover Plugins" Click="BtnSearchPlugins_OnClick"/>
        <Button x:Name="btnShowPlugin" Content="Display Plugin" Click="BtnShowPlugin_OnClick" Margin="0,10,0,0"/>
    </StackPanel>
</Window>

The corresponding code-behind handles plugin discovery and execution:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using AbstractionLayer;
using Path = System.IO.Path;

namespace WPFIPluginDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void BtnSearchPlugins_OnClick(object sender, RoutedEventArgs e)
        {
            LoadPlugins(GetCurrentProgramPath() + "\\Plugins");
        }

        public static string GetCurrentProgramPath()
        {
            var entryAssembly = Assembly.GetEntryAssembly();
            var location = entryAssembly.Location;
            return Path.GetDirectoryName(location);
        }

        public List<IPlugin> PluginList = new List<IPlugin>();
        
        public void LoadPlugins(string directory)
        {
            try
            {
                var files = Directory.GetFiles(directory, "*.exe", SearchOption.TopDirectoryOnly);

                foreach (var file in files)
                {
                    Assembly assembly = Assembly.LoadFrom(file);
                    var types = assembly.GetTypes().Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsInterface);

                    foreach (var type in types)
                    {
                        IPlugin instance = (IPlugin)Activator.CreateInstance(type);
                        instance.Initialize();
                        PluginList.Add(instance);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                throw;
            }
        }

        private void BtnShowPlugin_OnClick(object sender, RoutedEventArgs e)
        {
            Type pluginType = PluginList[0].GetType();
            MethodInfo method = pluginType.GetMethod("Show");
            method.Invoke(PluginList[0], null);
        }
    }
}

The plugin module WpfPlugin3 implements the IPlugin interface:

using System;
using AbstractionLayer;

namespace WpfPlugin3
{
    public class WpfPlugin : IPlugin
    {
        public MainWindow WindowInstance = null;
        
        public void Initialize()
        {
            WindowInstance = new MainWindow();
        }

        public void Show()
        {
            if (WindowInstance != null)
            {
                WindowInstance.ShowDialog();
            }
        }
    }
}

The plugin's main window is defined as follows:

<Window x:Class="WpfPlugin3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="450" Width="800" WindowStyle="None">
    <Grid>
        <Button Content="WpfPlugin3" Width="200" Height="200" />
    </Grid>
</Window>

To execute this setup, place the WpfPlugin3.exe file inside the Plugins folder under the debug output directory of WPFIPluginDemo.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.