Why Shouldn’t I use PRISM?

Introduction

PRISM, or Composite Application Guidance/Library for WPF/Silverlight, is a library and a corresponding guidance document that helps you to build loosely coupled “composite” WPF and Silverlight applications.

The library itself “sits on top” of an Inversion of Control Container (Unity by default), and provides facilities for modularising your application, composing your UI from components, loosely coupling events and, in Silverlight’s case, only downloading parts of your application as and when they’re required.

Sounds great doesn’t it?

So, There Must Be Something Wrong With It.. Right?

Plenty has been written about PRISM, its benefits, and how to get started; but very little on why you wouldn’t use it on your next WPF/Silverlight project. I’ve put together some concerns, based both on criticisms I’ve read, and supposition on my part; and some commentary about whether I believe those concerns are well founded or not.

“I’m Only Doing a Small Project!”

Granted, PRISM is rather overkill for “toy” applications; but are you sure your application is always going to stay that small and simple? One of the big advantages of the modular nature of a PRISM app is being able to add and test new features with relative ease. I’m sure we’ve all started projects that started off as a simple little toy app, but have since grown organically into something rather more complex – possibly ending up with some pretty kludgey code at the end of it.

“It’s Complicated!”

No; it’s not. Really. There’s nothing particularly complex in PRISM, either conceptually or in the code you have to write. Once you understand the structure of a PRISM project, you’ll probably find that your code is actually easier to follow, as it is separated into clearly defined parts.

If you want an easy to follow tutorial that takes you from File.. New, through to a working application, then take a look at the excellent screencasts from Blaine Wastell’s blog.

“It Takes Too Long To Use! There’s Too Much Overhead!”

If you’ve watched some of the initial screencasts about PRISM, or had a peak at some sample code, you might be thinking that the overhead of creating all these “extra” classes and projects is just too much. While it certainly is more work than just File.. New and throwing controls on a page; once your initial project structure and bootstrapper is setup, adding new modules is no more time consuming than adding a normal User Control.

Separating your view from it’s logic; whether it be with ViewModels, the Presentation Model, or any other pattern, is going to be slightly more work; but the testability and data binding benefits far outweigh any slight increase in typing!

“It Will Add Bloat to My Silverlight App!”

The PRISM binaries, including Unity, weigh in at around 270k; and squeeze down to approximately 100k when zipped. Not exactly tiny, but not exactly Bloaty McBloater. In fact, if you take advantage of PRISM’s ability to bundle parts of your Silverlight application into different XAP files, and only load them when needed, you may find your initial payload is actually smaller than it would be without PRISM.

“You Have To Use Unity! I Don’t Want That Dependency!”

I’ve seen this repeated several times, but it’s simply not true. Although PRISM “out of the box” uses Unity, and comes with a Unity Bootstrapper; you can plug in your own IoC container without too much trouble. At the time of writing I believe there are alternatives for Spring.Net, Castle Windsor and StructureMap already written for you.

“I Want Control Over *ALL* My Damn Code!”

Firstly, if you’re writing a .Net application then chances are you are calling at least one library that you didn’t write 🙂 Secondly, PRISM is very “lightweight”. It’s a helping hand at your disposal, rather than a monolithic framework that takes over your whole application and forces you to work in a certain way. Thirdly, you can just pick and choose which parts of PRISM you want to use, it’s not an “all or nothing” proposition. Don’t like the view composition? Then don’t use it! And finally, it’s all open source, so if you don’t like the way something works – change it! 🙂

“It’s From MS – So It Sucks!”

Unfortunately if someone holds this view, then there’s probably nothing anyone can say to change their mind. While everything that comes out of Microsoft isn’t perfect, far from it, it most certainly doesn’t all suck 🙂

With PRISM, the exceedingly smart guys from the Patterns and Practices team have created an excellent set of tools and guidance to help solve some very common problems; without producing a heavy, complicated framework in the process (CAB anyone? 🙂 )

“I Can’t Frikkin’ Find It!”

Ok, I admit it, you’ve got me on this one! 🙂 Is it on MSDN? Is it on CodePlex? Both?! Is it called PRISM? The Composite Application Library (CAL)? Or maybe Composite Application Guidance for WPF and Silverlight (CAG)?

Now CAL obviously refers to the library, CAG to the guidance, and I believe PRISM is an umbrella term for the whole project, but the naming is certainly confusing, and searching for PRISM takes you to CodePlex then MSDN and back again, so it’s very easy to get confused! In fact, finding, downloading and building the library is actually MORE confusing than using the damn thing! There is actually a whole article on Sparking Client on How to Find, Download and Build Prism for Silverlight, which speaks volumes 🙂

I really don’t see what’s wrong with calling the whole thing PRISM and leaving it at that. If I say  “.Net Framework”, then most developers would know what I mean. There’s certainly no need for me to call it the “Microsoft Framework for Building Managed Applications Targeting the Windows Platform (MFBMATWP)” 😉

Tell Me More!

If you want to know more about PRISM, or if you want some walkthroughs and examples of how to use it, then here’s some links that should float your boat:

WPF Bootstrapping, NotifyIcon, ShutdownMode and the Mysterious Vanishing Application!

Introduction

I’m currently working on a small utility called Hotwire, which should be released in the not too distant future. Part of the application consists of a “launcher” application that sits in the notification area (the bit by the clock :-)) and fires up various other parts of the app when the user needs them.

Originally I put it together as a WinForms app, which seemed logical as the NotifyIcon class lives in System.Windows.Forms anyway, but once I’d started putting the configuration dialog together, I realised how much I missed the Binding magic of WPF. Although shifting the app across to WPF was a relatively simple task, there were a couple of “gotchas” along the way.

The WinForms Way – Without a Window!

A lot of the samples you’ll see for using NotifyIcon in WinForms will create a Window, put the NotifyIcon class on the form, and hide the form on startup so all you’re left with is the icon by the clock. While this approach works, as this application doesn’t have a “main window” as such,  it seemed a bit naff to have a hidden Window lurking in the background that I’d never use.

To do things slightly more “elegantly” we can “bootstrap” our application manually with our own Main() method, and put together a class that creates all of the controls required for our NotifyIcon and it’s various menus. Our Main() method is very simple; we just set a few properties, instantiate our TaskTray class and call Application.Run() to give us our Windows message pump (if you don’t do the last part, your application will quit immediately!)

static class Program
{
    private static TaskTray t;
    
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        t = new TaskTray();
        Application.Run();
    }
}

Now our TaskTray.cs file will intentionally look spookily similar to the code behind for a normal WinForms window. All we need to do in our constructor is create a Container, a NotifyIcon, a ContextMenuStrip to attach to it, and an icon for us to display. To maintain parity with a normal codebehind class, we will wrap all of this up into a method called InitialiseComponent:

public void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.SysTrayIcon = new System.Windows.Forms.NotifyIcon(this.components);
    this.MainMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
    this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.configToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
    this.MainMenu.SuspendLayout();

    this.SysTrayIcon.ContextMenuStrip = this.MainMenu;
    this.SysTrayIcon.Icon = new System.Drawing.Icon(this.GetType(), "myapp.ico");
    this.SysTrayIcon.Text = "MyApp";
    this.SysTrayIcon.Visible = true;

    this.MainMenu.Name = "MainMenu";
    this.MainMenu.Size = new System.Drawing.Size(114, 82);

    this.MainMenu.Items.Clear();

    this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
    this.aboutToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
    this.aboutToolStripMenuItem.Text = "&About";
    this.MainMenu.Items.Add(aboutToolStripMenuItem);

    this.configToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
    this.configToolStripMenuItem.Text = "&Configuration";
    this.MainMenu.Items.Add(configToolStripMenuItem);

    this.MainMenu.Items.Add(new System.Windows.Forms.ToolStripSeparator());

    this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
    this.exitToolStripMenuItem.Size = new System.Drawing.Size(113, 22);
    this.exitToolStripMenuItem.Text = "E&xit";
    this.MainMenu.Items.Add(this.exitToolStripMenuItem);

    this.MainMenu.ResumeLayout(false);
}

We can then hook some events up in the normal manner and we’re all done, and no Window classes in sight!

The WPF Way – Still Without a Window!

To port this to WPF we first need to add references to System.Windows.Forms and System.Drawing (for our Icon), once that’s done we need to roll our own “bootstrapper” so we don’t create a Window on startup.

By default, when you create a new WPF application, you will get Window1.xaml and App.xaml. The latter contains a StartupUri property that the generated code behind uses to bootstrap the application and display the main window. If we nuke App.Xaml from the project (we’ll get a duplication Main() error if we don’t), we can add our own bootstrapper which looks very similar to the WinForms one above:

class BootStrap
{
    static TaskTray _taskTray;

    [STAThread]
    static void Main()
    {
        Application app = new Application();
        _taskTray = new TaskTray();
        app.Run();
    }
}

If you add our TaskTray class into this new project (making sure to add a Using statement for System.Windows), and fire it up we will get our NotifyIcon as before and it looks like we’re all done! Or are we… 🙂

What? Where Did My App Go?

If you decide you want to show a Window from one of your menu items, such as a configuration window, you’ll immediately notice that as soon as the user or application closes that window then your application will immediately quit!

The reason for this is down to the default behaviour of the WPF Application object. The Application object keeps track of all of the Windows opened (as well as a “special” MainWindow which is automatically set to the first Window that is created inside the Application) and when the last window closes, it terminates the application. This default behaviour makes sense for a “normal” application, because most of the time we WANT it to shutdown properly when all the windows are closed; but in our scenario it’s a huge pain in the ****!

The Fix

Our immediate reaction might be to create a “dummy” Window in our bootstrapper and keep it hidden somehow; but this is the same “hack” as the one I disliked from the WinForms version, so we really want to avoid doing that.

Luckily, we can override this behaviour using the ShutdownMode property on our Application object. We can tell it to either terminate only when the MainWindow window closes, or only shutdown when we explicitly tell it to (which is what we want for our application). This changes our bootstrap class to the following:

class BootStrap
{
    static TaskTray _taskTray;

    [STAThread]
    static void Main()
    {
        Application app = new Application();
        app.ShutdownMode = ShutdownMode.OnExplicitShutdown;
        _taskTray = new TaskTray();
        app.Run();
    }
}

We then need to make sure we call Application.Shutdown when we want to quit, which we can do from our Exit menu option:

this.exitToolStripMenuItem.Click += (s, e) => 
    { 
        Application.Current.Shutdown(); 
    };

You can grab the code below:

WpfNotifyIconTest.zip

Taking WPF “Screenshots”

I was recently working on a Surface project at Microsoft (that will be shown at BETT 🙂 ) and one of the requirements was to provide an external “administration console”.  As part of that console I wanted to show an “screenshot” of the current game running on the Surface unit; after playing around for a while it turned out it was pretty straightforward.

We did consider sending over the RAW XAML from the Surface to the Console, but that would potentially have issues when resources weren’t available, so the approach that was taken was to create a JPG screenshot and send it over as a byte array via WCF.

Rendering to a BitmapFrame

The key to this approach is RenderTargetBitmap which allows us to render any WPF Visual to a BitmapFrame as follows:

RenderTargetBitmap renderTarget = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
renderTarget.Render(myVisual);
BitmapFrame bitmapFrame = BitmapFrame.Create(renderTarget);

Then from there we can use JpegBitmapEncoder to create a JPG from that BitmapFrame:

JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.Frames.Add(bitmapFrame);

Then we can output that JPG to a stream of our choice using the Save() method.

Problems

While this works for many cases, and indeed worked perfectly for the Surface application, we do encounter problems when the source we are rendering has Transforms applied or when it’s not positioned at 0,0.  When this occurs the screenshots we take will have the content shifted“out of frame” resulting in black borders, or content missing altogether.  The following screenshot demonstrates the problem:

Shifted Content Problem

Workaround

To work around the problem we can use a VisualBrush to “draw” our source element onto a new Visual, and render that with our RenderTargetBitmap:

DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();

using (drawingContext)
{
    drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(200, 200)));
}
renderTarget.Render(drawingVisual);

It’s not ideal, but I’ve yet to find a better workaround for it.

Putting it all Together

To make it more useful, we can wrap the whole lot up into a Extension Method.  Rather than extending Visual, I’ve chosen to use UIElement so I have access to the RenderSize to calculate the required size of the output bitmap.  I’ve also included parameters to scale the resulting bitmap and to set the JPG quality level:

///
/// Gets a JPG "screenshot" of the current UIElement
///
/// UIElement to screenshot
/// Scale to render the screenshot
/// JPG Quality
/// Byte array of JPG data
public static byte[] GetJpgImage(this UIElement source, double scale, int quality)
{
    double actualHeight = source.RenderSize.Height;
    double actualWidth = source.RenderSize.Width;

    double renderHeight = actualHeight * scale;
    double renderWidth = actualWidth * scale;

    RenderTargetBitmap renderTarget = new RenderTargetBitmap((int) renderWidth, (int) renderHeight, 96, 96, PixelFormats.Pbgra32);
    VisualBrush sourceBrush = new VisualBrush(source);

    DrawingVisual drawingVisual = new DrawingVisual();
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    using (drawingContext)
    {
        drawingContext.PushTransform(new ScaleTransform(scale, scale));
        drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(actualWidth, actualHeight)));
    }
    renderTarget.Render(drawingVisual);

    JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
    jpgEncoder.QualityLevel = quality;
    jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));

    Byte[] _imageArray;

    using (MemoryStream outputStream = new MemoryStream())
    {
        jpgEncoder.Save(outputStream);
        _imageArray = outputStream.ToArray();
    }

    return _imageArray;
}

I’ve bundled the extension method class in with a small demo app and you can grab the source to both from here:

screenshotdemo.zip