View and ViewModel in external assemblies

Feb 15, 2011 at 9:52 AM
Edited Feb 15, 2011 at 9:55 AM
I have not really a question in this discussion, but want to share, how I managed to use views and viewmodels from an external assembly. I think it's really simple for those who are professionals, but for me as a hobby programmer it was a real success. It took me some time to put all necessary pieses together, so I thought it would be a good idea to write this discussion.

My goal is a base application with some features provided and the possibiltiy to extend it with addins. The addins should be dll's in a separate directory. So the first step is to make a few chances in the bootstrapper:

        private IEnumerable<Assembly> GetExtensions()
        {
            List<Assembly> assemblies = new List<Assembly>();
            string extensionsDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) +
                                             "\\Extensions";

            if (System.IO.Directory.Exists(extensionsDirectory))
            {
                foreach (string file in System.IO.Directory.GetFiles(extensionsDirectory, "Brose.Test.Extension*.dll"))
                {
                    assemblies.Add(System.Reflection.Assembly.LoadFile(file));
                }
            }
            return assemblies;
        }
       
        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            List<Assembly> assemblies = new List<Assembly>();
            
            assemblies.Add(Assembly.GetEntryAssembly());
            assemblies.AddRange(GetExtensions());
            return assemblies;
        }

The bootstrapper now searches for files beginning with "Brose.Test.Extensions*" in a specific directory and adds them to the AssemblySource (via SelectAssemblies).

In the external Assembly the ViewModels are exported as ITools (or whatever else you want). The Interface ITool is provided in a "core"-Assembly, so the Extensions know only the core-Assembly.

    [Export (typeof(ITools))]
    public class ToolOneViewModel : Screen, ITools
    {
        public ToolOneViewModel()
        {
            DisplayName = "Extension One";
        }

    }

All found Extensions are imported in the constructor of the MainViewModel (yes, you would call it Shell, but thats my decision)

[Export(typeof(IMainWindow))]
    public class MainWindowViewModel : Conductor<ITools>.Collection.OneActive, IMainWindow
    {
        [ImportingConstructor]
        public MainWindowViewModel([ImportMany] IEnumerable<ITools> tools)
        {
            DisplayName = "AddIn Test";

            Items.AddRange(tools);
        }
    }

In the MainView the Extensions are display as TabControl

<Window x:Class="Brose.Test.CaliburnMicroAddIns.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel>
        <TabControl x:Name="Items"></TabControl>
    </DockPanel>
</Window>

It's only a testapplication but I hope it will work fine for me in the next step.

Feel free to comment and improve this solution. As mentioned above, it's only hobby for me.

 

Edit: I forgot to tell, that I really like Caliburn.Micro. It's the first MVVM-Framwork that seems to fit to me. Thanks, Rob!