Saturday, January 26, 2013

Using Addins in WPF

I was starting to program an idea I've had, you know what they say, Necessity is the mother of invention... 

Its about unifying all the notifications in my daily tasks, RSS, emails, website updates (that didn't bother implementing RSS), etc' into one place, under one application, with each one able to trigger its own workflow, execute applications, popup on screen, queue messages in the systray and more.

So, one of the first things to do when writing an application like that, is to make it pluggable, makes it easy to extend the functionality in a very easy manner.

When developing such an application, one needs a way to configure each plugin, eventually I've figured out a way to do it in WPF.

I'm using composition for simplicity, from performance point of view, you might want to use the alternative I offered here

ApplicationPlugins = _container.GetExportedValues<IWPFApplicationPlugin>();


The way I'm doing it is creating a container window which has cancel and ok buttons and a grid which will later contain the user control from the plugins.

<Window x:Class="WPFApplication.SettingsWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SettingsWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        d:DesignHeight="386" d:DesignWidth="501" SizeToContent="WidthAndHeight" Closing="Window_Closing">
    <Grid Width="Auto" Height="Auto">
        <Button Content="Ok" Height="25" HorizontalAlignment="Right" Margin="0,0,12,12" Name="btnOk" VerticalAlignment="Bottom" Width="98" Click="btnOk_Click" />
        <Button Content="Cancel" Height="25" HorizontalAlignment="Left" Margin="12,0,0,12" Name="btnCancel" VerticalAlignment="Bottom" Width="98" Click="btnCancel_Click" />
        <Grid Margin="12,12,12,43" Name="UCContainer" Width="Auto" Height="Auto"  />
    </Grid>
</Window>


When a user wants to add another record from a specific plugin, I open up a new window, populate the UCContainer's children with the user control from the plugin and display it.


public bool? ShowDialog(IWPFApplicationPlugin plugin, string data)
{
    this.m_plugin = plugin;
    var uc = this.m_plugin.GetUserControl();
    this.m_plugin.Reset();
    if (data != null)
        this.m_plugin.SetData(data);
    this.UCContainer.Children.Add(uc);
    this.UCContainer.MinHeight = uc.MinHeight;
    this.UCContainer.MinWidth = uc.MinWidth;
    return this.ShowDialog();
}


After looking it for myself and seeing people struggling with setting the window's MinWidth/MinHeight based on the content, here's how I got it:


private void Window_Loaded(object sender, RoutedEventArgs e)
{
    Size margin = new Size();
    FrameworkElement contentElement = this.Content as FrameworkElement;
    if (contentElement != null)
    {
        margin.Width = this.Width - contentElement.ActualWidth;
        margin.Height = this.Height - contentElement.ActualHeight;
    }

    Rect size = VisualTreeHelper.GetDescendantBounds(this);

    this.MinHeight = size.Height + margin.Height;
    this.MinWidth = size.Width + margin.Width ;
}

You can find the project at:
https://github.com/drorgl/ForBlog/tree/master/WPFPlugins



No comments:

Post a Comment