For an introduction to the SoapBox.Core (SBC) framework, read Building an Extensible Application with MEF, WPF, and MVVM.
The demo project that is introduced with the SoapBox framework is a pinball game. It demonstrates a few things that the framework provides, but is missing a few that
are integral to many applications. A toolbar, for example.
I did not find the pinball example particularly useful for my own use and started writing code to figure
out how various parts of SBC work in a simple example of my own. I figured I would share my results here.
Also, as it's written, the SoapBox framework is a set of projects within solution folders, and SoapBox.Core.Host is output as an executable. So using SoapBox requires that we include the whole set of SoapBox projects within our local solution and set SBC Host as the startup project. There are several problems with this:
- Including these extra projects is kind of messy (and can increase compile time).
- When SoapBox has an update, updating the SoapBox projects in all of our projects is messy.
- The Express editions of Visual Studio don't support solution folders (they also don't support mixed languages, so can't use the SoapBox C# sources within, say, a Visual Basic project). (As a workaround, you can use SharpDevelop or MonoDevelop (buggy?) to open projects that use solution folders or mixed languages.)
So for this article, first I will describe how to set up the SoapBox.Core.Host so the SBC can be used as a set of DLLs. The example project also moves the DLLs into separate folders instead of having them all in the application's base folder.
Second, I will present a simple example solution containing a startup project and a "feature" project that has some basic things most applications need (toolbar, status bar, document area, etc.).
First, change the project type from WinExe to Library.
Second, rename App.xaml.cs to App.cs and remove App.xaml.
The attached source code has the details for the new file. It is mainly a copy of App.xaml.cs, plus some things I added for setting and accessing its catalog.
You may also need to manually remove this line from SoapBox.Core.Host.csproj:
Now you can build the SoapBox solution and then copy whichever DLLs you want to use to your own project library.
Creating the Startup Project (Example.Host)
This project outputs the executable file that starts the application. Pretty much all it does is provide references to the SBC DLLs and then set up and run the framework. Then the framework does the rest of the work. Here's a step-by-step.
- Start the editor (I am using Visual Studio C# Express 2010).
Create a new project (New > Project > WPF Application), named Example.Host
Save Example.Host As ...
SolutionName: Example (Create directory for solution)
- In Windows Explorer (not Visual Studio), create a folder (named Lib) in the solution folder and put all of the SoapBox, NLog, and AvalonDock DLLs in it.
- Add references to all of the DLLs in the Lib folder. We need references to all of these with the Visual Studio "Copy Local" property set to true, even though Example.Host doesn't explicitly need some of them, so they get copied to the output folder. (This is one way to do it; there's a number of different ways to get these copied to the output folders.)
- Add a reference to System.ComponentModel.Composition
App.xaml, MainWindow.xaml, and related .cs files.
Program.cs with a Main that creates a new
- Add catalogs to the app object, so SBC knows where to look for them.
- Add a call to Run() on the app object.
- Change the build Location to ..\bin\Debug and ..\bin\Release (Be *sure* that all projects output to the correct folders or you will be scratching your head when things don't appear in the application when you run it).
- At this point, if you run the project, you should get a plain workbench (bigger than the screenshot, but otherwise the same).
Creating an Example "Feature" Project (Example.HelloWorld)
For each main "feature" of your application, you'll want a separate project. For a more loosely coupled solution, all features would refer to common project, such as the "Contracts" project that appears in SoapBox examples. For simplicity (and because there's only one feature), all of the contracts are in HelloWorld (see the
ExtensionPoints files in the source code).
You might also want to set up one of the features (or even the 'host" project above) as the main shell, to provide a "main" toolbar, about box, etc.
The example application demonstrates the following items:
- Application icon. SoapBox examples use a way that the author comments as "hacky", which creates a Window class and sets the icon with the VS designer... I implemented a "less hacky" one- or two-liner method that reads the image as an embedded resource. Namely,
Uri u = new Uri("pack://application:,,,/Example.HelloWorld;component/App/star.png", UriKind.Absolute);
mainWindow.Value.Icon = new BitmapImage(u);
SBC StartupCommands (Shutdown commands are similar). The startup command in this example is used to display the recipe document and instructions pad when the application starts.An SBC Pad (the pinball demo uses a pad, as well). An SBC Document. SBC Document and Pad XAMLs are based on ResourceDictionaries with a DataTemplate, which are not editable in Visual Studio designer. This example demonstrates referencing a UserControl so that the Visual Studio designer CAN be used to edit the layout. Not a big advantage for a simple example like this, but great if the layout is more complex.An SBC ToolBar with a ToolBarButton that is linked via an
IExecutableCommand to perform some action (display a MessageBox). An SBC StatusBar with several different items in it.Adding items to the menu (such as the About item).
Here is the most basic step-by-step, as a recipe for creating one of these projects.
- Add a New WPF project, named Example.HelloWorld, to the solution. I find this easier than using a library project and then having to add all of the WPF references.
App.xaml, MainWindow.xaml, and associated .cs files.
- In the project properties, change the project type to Class Library.
- Add a reference to System.ComponentModel.Composition
- Add a reference to Soapbox.Core.Contracts
- Change the build Location to ..\bin\Debug
- Start adding SBC items by using Export and Import as needed....
Points of Interest
For downloading the SoapBox Core and related projects from its author, visit SoapBox Core. For FAQs and some quick examples, visit ask.soapboxcore.com.
I messed around for a while trying to figure out how to merge the SBC DLLs into a single file. ILMerge, the traditional method, doesn't work for WPF. Several other methods I tried didn't work and gave me various errors that I think meant MEF couldn't find the correct assemblies or that the same assembly was being loaded in different contexts.
Troubleshooting loosely coupled projects can be tricky. Here's an interesting reference: How to Debug and Diagnose MEF Failures.
2012-02-12: First edition.