A picture of me

Welcome, my name is Paul Stovell. I live in Brisbane and work on Octopus Deploy, an automated deployment tool for .NET applications.

Prior to founding Octopus Deploy, I worked for an investment bank in London building WPF applications, and before that I worked for Readify, an Australian .NET consulting firm. I also worked on a number of open source projects and was an active user group presenter. I was a Microsoft MVP for WPF from 2006 to 2013.

Here's a list of things I'd like to see in the next version of WPF:

  1. Blend's Behaviors and TriggerActions model should be part of the .NET framework, not a custom Blend assembly, and should have VS support
  2. I shouldn't have to declare the same half-dozen xmlns:abc entries in every XAML file. An ASPX inspired 'project-wide imports' system would be great.
  3. Ability to replace tags from a namespace, ala ASP.NET TagMapping.
  4. This should work for markup extensions too - e.g., {# Foo} could become {Binding Path=Foo}
  5. XBAP's should be able to nicely prompt for full trust elevation. Why does Silverlight get a friendly prompt while XBAP's have to deal with group policy or arcane IE settings? Boggles the mind.
  6. MarkupExtension should be an interface. Then extensions could be DependencyObjects and thereby support attached properties.
  7. It shouldn't be so hard to support nested child objects with bindings (without using ItemsControl).
  8. FrameworkElement.AddLogicalChild shouldn't be protected, it should be public
  9. Styles simply shouldn't be so verbose. Give us a CSS-like syntax for styles.
  10. ICommands should have the ability, when executed, to determine which UIElement owns the command. Perhaps when event handlers are invoked, CallContext could be used to store the current UIElement 'sender'.
  11. AdornedElementPlaceHolder shouldn't be so tightly coupled to TemplatedAdorner. Or, TemplatedAdorner shouldn't be internal.
  12. Easier to make attached lazy collections (without the current 'hacks').
  13. Fix this bug.
  14. Some kind of pre-unload event. E.g., if an object is removed from an ObservableCollection, make it as easy to play an Unloaded storyboard as it is for a Loaded storyboard. Perhaps it's specific to the item containers of an ItemsControl.
  15. Make it possible to figure out the XAML URI from a Type. E.g., this should pass:
    Assert.AreEqual("/MyAssemb;component/Page1.xaml", GimmeUri(typeof(Page1)))
  16. Make it possible to set a default style for x:Class root's (e.g., a style for all Window's) - as per this question.
  17. TriggerBase's constructor shouldn't be public
  18. Delete everything from System.Windows.Navigation, and build a better navigation system.

I have written before about the inherent problems with WPF's navigation engine, but thus far I have avoided the "roll your own" solution. Recently I started work on a Silverlight version of Magellan, and despite a promising start, I ran into similar problems with the Silverlight Navigation Framework. Where in the WPF version I was content to just live with the problems, the Silverlight version simply wouldn't work - URL's would be broken and the 'back' button would bypass controllers completely. So until I do this there will be no Silverlight Magellan.

This means that Magellan, which was originally all about MVC, is getting it's own navigation framework. Here are some design goals:

Design Goals

  • Memory management strategies should up to the developer. If a developer wants to keep a page in memory, they should be able to. If they want to have it garbage collected on a new navigation request, it should (in WPF, you can't be GC'd, and in Silverlight, you can't keep it in memory).
  • Developers should be able to control the construction of pages. None of this "must have a parameterless constructor" baloney.
  • Should be optional. Magellan will continue to work with the inbuilt frameworks, this will just be better.
  • Works with the browser back/forward button and URL's. This seems to be easy in Silverlight, but not so easy for WPF XBAP's, so we'll see.
  • Is based on SOLID principles and well tested. I've read the source code to NavigationService. It's a 4,783 line class. I can understand why it has design problems and hasn't changed since 2005 :-)
  • A lot more control over the back and forward stacks

I don't like the idea of forcing views to inherit from certain classes to work within a navigation system. Ideally, a "page" should just be a FrameworkElement or greater (most probably a UserControl). A "frame" should just be a ContentPresenter. There should be no need to derive from a whacky MagellanPage base class.

I'll draw a lot of inspiration from ASP.NET's concepts of IHttpHandlers and IHttpModules and the routing engine, as well as frameworks like nRoute. The concepts of URI's and route handlers will be vastly seperated from the concepts of pages and content.

(More to come)

Magellan

I have migrated the Magellan source code and releases to CodePlex.

http://magellan.codeplex.com

A few benefits to using CodePlex are:

  • I use TeamCity to publish releases for each check in (thanks to the MSBuild Deployment Tools project). The releases are hidden at first (in case they have problems) and once I have tested them they become public.
  • You can use the RSS feed to stay up to date.
  • You can use the Issue Tracker to report bugs.
  • You can use the online source code browser to see the source.
  • You can use CodePlex to submit a patch if you run into any bugs or have any ideas.

I plan to keep the documentation on the Magellan home page of this blog as it gives me better control of the markup. I have migrated all of the change sets to CodePlex using the SVN2SVN project, and I'll be clearing out the original source code location soon (I'll keep it on line though in case the CodePlex history is incomplete).

It seems that every WPF developer has written a Model-View-ViewModel library, and I was starting to feel left out. Having written an MVC and MVP framework, I figured I may as well write an MVVM library. But I want it to be different - I want the ViewModels to be as small as possible. That's how MicroModels was born.

MicroModels is inspired by Fluent NHibernate and uses TypeDescriptors to dynamically define properties, collections and commands.

In the example below, the view model exposes the FirstName and LastName properties of the customer object. The LastName property is renamed to Surname, and a FullName property is defined using the two names. It also exposes a Save ICommand property that saves the customer to the repository.

public class EditCustomerModel : MicroModel
{
    public EditCustomerModel(Customer customer, CustomerRepository customerRepository)
    {
        Property(() => customer.FirstName);
        Property(() => customer.LastName).Named("Surname");
        Property("FullName", () => string.Format("{0} {1}", customer.FirstName, customer.LastName));
        Command("Save", () => customerRepository.Save(customer));
    }
}

What? That's it? Where's the INotifyPropertyChanged? The getters and setters? Don't worry, it's all done at runtime by MicroModels :)

The dynamic properties are available for data binding in XAML:

<DockPanel>
    <ToolBar DockPanel.Dock="Top">
        <Button Content="Save" Command="{Binding Path=Save}" />
    </ToolBar>

    <Border Background="#f0f0f0">
        <StackPanel>
            <WrapPanel Margin="1">
                <Label Margin="1" Width="130">FirstName</Label>
                <TextBox Margin="1" Width="50" Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
            </WrapPanel>
            <WrapPanel Margin="1">
                <Label Margin="1" Width="130">Surname</Label>
                <TextBox Margin="1" Width="200" Text="{Binding Path=Surname, UpdateSourceTrigger=PropertyChanged}" />
            </WrapPanel>
            <WrapPanel Margin="1">
                <Label Margin="1" Width="130">Full Name</Label>
                <Label Margin="1" Width="200" Height="50" Content="{Binding Path=FullName}" />
            </WrapPanel>
        </StackPanel>
    </Border>
</DockPanel>

Dependency Analysis

MicroModels makes use of expression trees to analyse the dependencies a property has. In the code example above, MicroModels can figure out that the FullName property depends on the FirstName and LastName properties. If the customer raises a PropertyChanged event for either of those properties, MicroModels will raise a property changed event for FullName.

Multiple Sources

Perhaps instead of a view model exposing properties from a single object, your ViewModel will union multiple objects together. That's easy:

public class CompareCustomersModel : MicroModel
{
    public CompareCustomersModel(Customer left, Customer right)
    {
        AllProperties(left).WithPrefix("Left");
        AllProperties(right).WithPrefix("Right");
    }
}

From XAML you could bind to properties such as LeftFirstName and RightFirstName.

Wrapping Child ViewModels

If you had Order and LineItem business objects, it's common to create an OrderViewModel and LineItemViewModel, and to expose the Order's LineItems as a collection of LineItemViewModel's.

With MicroModels, this is no longer necessary. MicroModels can expose a collection of child items, and automatically wrap each item in a MicroModel. The example below shows how LineItems might be exposed as a collection, and adds a LineTotal property to each child item:

public class InvoiceViewModel : MicroModel
{
    public InvoiceViewModel(Order order, IEnumerable<LineItem> lineItems, IOrderService orderService)
    {
        AllProperties(order);

        Collection("LineItems", () => lineItems)
            .Each((item, model) => model.Property("LineTotal", () => item.UnitPrice * item.Quantity));

        Command("Save", () => orderService.Save(order, lineItems));
    }
}

When the Quantity of a single LineItem changes, MicroModels detects the changes and raises an event for the dynamic LineTotal property.

Get Started

You can download the binaries and reference MicroModels.dll. ViewModels just have to inherit from the MicroModel base class. You can also check out the source which includes a couple of samples. There is some work to do around documentation, improving the extensions system and cleaning it up. The public API needs some work, and I'd be really interested in what people think about some of the naming conventions used.

I have seen some confusion around the naming of the major UI presentation patterns, often with code being described as one pattern when actually it uses a different one. This usually happens because the goals behind each pattern are similar and the descriptions are a little too theoretical. I want this page to serve as a practical description of each pattern and to provide some concrete examples of what differentiates the patterns in the wild.

The Three Major UI Patterns

The three UI patterns commonly used in WPF applications are Model-View-Controller, Model-View-Presenter and Model-View-ViewModel (MVC, MVP and MVVM respectively).

Model View Controller

MVC was the original pattern, but the description of the pattern and the reality of how it is used have evolved. Fowler's page on the subject describes a controller as co-ordinating the behavior of a view, as if there were one controller per view. From the original Smalltalk MVC paper:

Each view is associated with a unique controller and vice versa

By that definition, we should expect controllers to look like this, with each controller clearly associated with one and only one view:

public class EditCustomerController : Controller<EditCustomerView>

Anyone who has used a web based MVC framework, however, has seen a very different style of implementing MVC. The success of recent MVC frameworks like Ruby on Rails, ASP.NET MVC and Zend have changed the working definition of MVC to a controller that handles many views. Controllers in this style typically look like:

public class CustomerController : Controller
{
    public ActionResult List();
    public ActionResult Show(int customerId);
    public ActionResult Edit(int customerId);
    public ActionResult Save(Customer customer);
    public ActionResult Delete(int customerId);
}

Where each of the actions return a different view.

I think there is an argument to be made that Zend, ASP.NET MVC and Rails aren't actually MVC, because Controllers deal with multiple views, when the original definition clearly said they should be unique. But that's only at design time - at runtime, when a request is received, the controller typically only creates one view per request, so perhaps it does meet the definition. It's a very blurry line that I'm not sure I want to get in the middle of.

Either way, MVC has come to mean a controller that handles many requests for different views, so that's the definition I use. Controllers tend to focus on navigation between views, rather than long-running interactions with a single view. Magellan has this focus.

Model View Presenter

MVP is described as a derivative of MVC. But when you see working examples of MVP, they tend to look just like the original definition of MVC, with a unique presenter per view. WebFormsMVP is an framework for this for ASP.NET. Caliburn is an MVP framework for WPF. I've also posted an example of building your own for WPF.

MVP has been further split into two approaches - Supervising Controller and Passive View. Supervising Controller is the version that almost everyone uses, and closely matches the original MVC definition. Passive View provides even more testability, and would be possible in WPF by exposing every Routed Event and the controls directly to the presenter, but I have never seen it implemented in WPF (and I don't think I would want to).

MVP in the form of Supervising Controller looks extraordinarily similar to MVC. The major difference is suggested in this snippet on Supervising Controller:

For input response the controller operates in the presenter style. The user gestures are handled initially by the screen widgets, however all they do in response is to hand these events off to the presenter, which handles all further logic.

This is the critical difference. In MVC, the controller gets the event first, before the view does. In MVP, the view gets the event first and gives it to the presenter.

On the web we can see how that works - user input happens in the form of HTTP requests, so controllers handle those and then render the view. But in WPF, controls always accept the user input first - the controller can never handle the input before the view.

Model View ViewModel

Fowler described this as the Presentation Model pattern, but WPF and Silverlight developers have come to know it as the MVVM pattern thanks to a John Gossman article. The Wikipedia article on MVVM has the history, but basically, MVVM is a specific example of Presentation Model in WPF and Silverlight applications. Personally, I use it because the first two patterns start with "MV" so the third may as well too.

MVVM is similar to MVP, but the ViewModel contains both state and behavior, while in MVP the state is generally kept in the model. The other major difference is that in MVP, where the Presenter references the View and can tell it what to do, in MVVM the ViewModel doesn't reference the View - instead, the ViewModel exposes properties and raises events that the View subscribes to.

Summary of Patterns

  • Model View Controller: Controller is concerned with navigation, and handles requests for many views. Controller typically creates the view and forgets about it. Controller gets user input before view.
  • Model View Presenter: Presenter is concerned with a single View. The presenter and view have a meaningful conversation. Model holds state, presenter contains behavior. View gets user input and passes to presenter.
  • Model View ViewModel: Much like MVP, but ViewModel contains both state and behavior. The ViewModel shouldn't have a reference to the View.

Identifying the Patterns

When you build a framework or spot some code, here are some concrete things to look for to identify the pattern. I'll use the term co-ordinator to refer to the third object in each pattern (Controller, Presenter or ViewModel).

  • If the co-ordinator has a reference to the view, you might be using MVP.
  • If the view is bound to properties on the co-ordinator, or the co-ordinator is the DataContext of the view, you might be using MVVM.
  • If the co-ordinator deals with navigation between multiple views, you might be using MVC.
  • If the view calls methods on the co-ordinator, you might be using MVVM.
  • If the view has to pass user input events to the co-ordinator, you might be using MVP.

Smalltalk-style MVC is impossible in WPF

As described above, in MVC, the controller gets input first, before the view. In MVP, the UI gets the input, and forwards it to the presenter.

An example is MVC4WPF. Controllers in MVC4WPF are associated with a single view and typically look like:

public class CustomerController : WPFViewWindowControllerBase<ICustomerView>

This looks similar to the Smalltalk type of MVC. But when I click a button, the view forwards that event to the controller. Based on the Supervising Controller definition above, this is really MVP, not MVC. The only way to achieve this style of MVC in WPF would be to have the controller handle events before the view - impossible with WPF.

I have owned a copy of Sams Teach Yourself WPF in 24 Hours for about a year, and I still find it an interesting book. One thing I like about this book is that doesn't just show off WPF features - it shows how to use the Model-View-Presenter pattern in doing so. The book was written by Rob Eisenberg and Christopher Bennage from BlueSpire, who are also the guys behind the Caliburn WPF framework, so they know a thing or two about the Model-View-Presenter pattern.

Like the Model-View-ViewModel pattern, we can mostly agree upon what the MVP pattern is, but in practice nearly every implementation looks different. I want to highlight some of the differences between my approach to MVP and theirs, and I have attached a sample application that demonstrates these.

Sample

As in the Teach Yourself WPF in 24 Hours book, my sample application is a contact manager. Here are the key points:

  • The application has a shell, and a docking panel like Visual Studio.
  • There are two types of views that can be opened - a Contact List, a Contact Details for an individual contact
  • It uses Composite WPF for region management and loosely coupled communication
  • It uses Autofac 2.0 Beta for IOC
  • It uses AvalonDock for tab management

You can download the code to follow along. You can also download the Teach Yourself WPF Contact Manager from the Sams website (you may need to register before the download appears).

Contact Manager Composite WPF with MVP Sample

Model-View-Presenter Differences

First let's highlight some differences in terms of approaches to the MVP pattern between the two. Martin Fowler splits the MVP pattern into Passive View and Supervising Controller, but if anything I think both approaches are Supervising Controller, just in a different way.

View->Presenter Communication

The first example is in how views and presenters communicate. In Teach Yourself WPF, views can hold a reference to the presenter - the following code is for a button click event handler:

private void Save_Click(object sender, RoutedEventArgs e)
{
    Presenter.Save();
}

An illustration of View-Presenter communication in Teach Yourself WPF

In my approach to MVP, Views should be independent of the presenter and not hold a reference to it, though they may be bound to a Model. If a view really wanted to communicate with a presenter, it would do so via raising an event:

event EventHandler SaveRequested;

private void Save_Click(object sender, RoutedEventArgs e)
{
    var handler = SaveRequested;
    if (handler != null) handler(this, EventArgs.Empty);
}

An illustration of View-Presenter communication the traditional way

(Of course, this is assuming that in both examples, we aren't using WPF Commands)

Some considerations to keep in mind here are:

  • In the Teach Yourself WPF way, the Presenter needs a reference to the View, but the View also needs a reference to the Presenter. For loose coupling to work, both of these should be interfaces, which may require a second interface. Using events, you normally create an interface for the view - there is no need for an interface for the presenter, since the view does not need to reference it.
  • On the other hand, testing is made a little easier with Teach Yourself WPF approach. To simulate the click event, you just have to call the method on the presenter. But to simulate the click event in the eventing approach, you have to mock the view and raise the mock event.

Presenter is DataContext?

One pattern the Teach Yourself WPF book uses, and Caliburn too, is that the Presenter is normally the DataContext for the view. This is different to the approach I've normally used, where data context is a separate object - either a domain model object, or a view model object that the presenter manipulates.

One benefit of this is that in the Teach Yourself WPF approach, properties on the presenter are available for direct binding. A presenter can use some code like this:

public void Initialize() 
{
    Contact = LoadContactFromDatabase();
}

public Contact Contact { get; set; }

However, in my approach, the presenter normally sets properties on a Model object, which it assigns to the view:

public void Initialize() 
{
    View.Model = new ContactDetailsModel();
    View.Model.Contact = LoadContactFromDatabase();
}

The Model property on the view is just a wrapper around the data context, but the key point is the DataContext is not the presenter - it is a different object. The presenter can manipulate the model, and the view can manipulate the model, but the view doesn't touch the presenter (except perhaps indirectly via raising events).

A similar thing happens with Commands. In Teach Yourself WPF/Caliburn, a command would be exposed to the view by a property on the presenter. In my approach, the presenter gives the command to the model, and the view gets it from the model.

public void Initialize() 
{
    View.Model = new ContactDetailsModel();
    View.Model.Contact = LoadContactFromDatabase();
    View.Model.SaveCommand = new DelegateCommand(SaveExecuted);
}

Here are some points to consider:

  • The Teach Yourself WPF approach is simpler because it requires less code - you don't have to create a separate class for the model.
  • However, it does put both state and behavior in the same object. In the approach I have used, state and behavior are separated.

Is it MVVM?

Though Teach Yourself WPF/Caliburn use the term presenters, some of the points above make me feel almost as if they are closer to the MVVM pattern than the MVP pattern. In MVVM:

  • The ViewModel is usually the DataContext (check)
  • The View binds to properties on the ViewModel (check)
  • The View holds a direct reference to the ViewModel (check)
  • The ViewModel typically contains both the state of the view and it's behavior (check)

The one thing Caliburn and Teach Yourself WPF do that wouldn't fit the MVVM profile is that the Presenter holds a reference to the View - something ViewModels should never do. However, in many ways it feels that the Presenters in Teach Yourself WPF/Caliburn are closer to the MVVM pattern than they are to the traditional MVP pattern.

Model-View-Presenter-Parameter

Another object that I have created for each view is a Parameter object. When you open a view, it's common to need to pass arguments to the presenter - such as a customer ID, filter information, and so on. Instead of making these properties on the presenter, the pattern I follow is to put them in a separate object. This is a technique I learned at from a client, and though it seemed redundant at first, it has grown on me.

For example, in the sample application, when you click a contact, the ContactDetailsPresenter is shown for that contact. The parameter object looks like this:

public class ContactDetailsParameter : Parameter
{
    public ContactDetailsParameter() : this(0)
    {
    }

    public ContactDetailsParameter(int contactId)
    {
        ContactId = contactId;
    }

    public int ContactId { get; set; }
    public bool IsNew { get { return ContactId == 0; } }
}

The presenter can make use of these arguments when initializing the view:

public class ContactDetailsPresenter : Presenter<IContactDetailsView, ContactDetailsModel, ContactDetailsParameter>
{
    protected override void Initialize()
    {
        View.Model = new ContactDetailsModel();
        View.Model.SaveCommand = new DelegateCommand(SaveExecuted);
        View.Model.Contact = Parameter.IsNew 
            ? new Contact() 
            : _contactRepository.GetContact(Parameter.ContactId);
    }
}

The key benefit that parameters have is that you can use them to identify information about a view, without actually creating the presenter or view. This is common when you want to re-activate an existing view.

In the sample application, you can click a contact and they will open in a new tab. If you click another contact, another tab opens. But if you click the same contact a second time, you don't want a new tab to appear - instead, you might want the currently open tab to get focus.

To open a view, I normally raise a Composite WPF event:

private void ShowContactExecuted(Contact contact)
{
    EventAggregator.GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ContactDetailsPresenter), "ContentPane", new ContactDetailsParameter(contact.Id)));
}

The arguments are:

  1. The type of presenter
  2. The region name to insert the view into
  3. The parameter, with all the arguments the presenter needs

There is a singleton event listener which receives that event and works something like this (simplified):

if (region.HasMatchingView(parameter))
{
    region.ActivateView(parameter);
}
else 
{
    var presenter = Container.Resolve(presenterType);
    region.Add(presenter.View, parameter);
}

The logic for deciding whether to re-use the view in the parameter is implemented like this:

public ContactDetailsParameter(int contactId)
{
    ContactId = contactId;

    // Use the same view when ContactID's match, but for new views, never reuse them.
    ReuseViewBy(() => IsNew ? (object)Guid.NewGuid() : ContactId);
}

While this approach has many upsides, it does increase the number of files needed for a full MVP view:

Solution Explorer showing views

The upside however is that you do get a flexible, consistent approach to views that can handle pretty much any scenario - and having used this pattern in a fairly complicated LOB application, I'm pretty confident that it can handle anything. A good New Item template for Visual Studio can greatly speed up the getting started time too.

Some things to consider:

  • A parameter is a good way to encapsulate the arguments for a presenter
  • But it does introduce an extra class, though that in itself has some benefits

Composite WPF Regions vs. Presenter Hierarchies

I have used Composite WPF in five client projects now and I'll continue to do so. It's a fantastic piece of work that does help you to solve many common scenarios without being overly controlling. The major feature Composite WPF brings for me is regions, which allow you to compose and nest views, and allow the to communicate via the event aggregator.

Composition is an aspect of Teach Yourself WPF/Caliburn that I really don't feel comfortable with, especially from a Composite WPF background. Check out the Caliburn documentation on presenters. Depending on your UI, you can choose from:

  • Presenter
  • Navigator
  • PresenterManager
  • MultiPresenter
  • MultiPresenterManager?

Each of these are kinds of presenters and serve to fulfill a specific composition pattern. They are necessary because, for example, if you have a view with two child views, the parent view's presenter needs a reference to the child presenters, and vice-versa sometimes, so they can communicate. It reminds me of the CAB SmartPart/Workspace approach.

The Composite WPF region approach does away with all of this. Here's the start up code for the sample application:

_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ShellPresenter), "Shell", new ShellParameter()));
_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(MenuPresenter), "Menu", new MenuParameter()));
_container.Resolve<IEventAggregator>().GetEvent<ShowViewEvent>().Publish(new ShowViewRequest(typeof(ContactListPresenter), "ContentPane", new ContactListParameter()));

This code opens the Shell, and injects the Menu and ContactList into it. However, the Shell view has no notion of either of them - the ShellPresenter is just a presenter, not some kind of MultiPresenterManager. If it needed to communicate with them, it could do so via a loosely coupled pub-sub model called the Event Aggregator.

Keep in mind that the Composite WPF region system would work just as easily with a Teach Yourself WPF presenter approach (presenter as DataContext, etc.). The composition approaches aren't necessarily exclusive either - hierarchical presenters as used with Caliburn can work alongside regions.

Conclusion

In this post I focused on two alternative approaches to implementing the Model View Presenter pattern - a traditional, strict approach with strong separation between state and behavior, and the Teach Yourself WPF/Caliburn approach which is a nice intermediary between MVP and MVVM. I think both patterns have their strengths and I've tried to provide some ideas on what those might be. I also contrasted the related composition approaches which aren't necessarily exclusive. I'd love your comments on additional strenghts/weaknesses you've experienced with either pattern.

And if you are building WPF line of business applications and haven't picked up a copy of Teach Yourself WPF, I'd definitely recommend it. This post is also not a thorough representation of the features that Caliburn nor Composite WPF provide - Caliburns Actions are definitely worth a look.

I enjoyed reading this question on Stack Overflow: What is (functional) reactive programming? I thought I'd take a stab at an explanation of what reactive programming means to me. Let me take you to the future.

The year is 2051, and our team of code anthropologists discovered some ancient script in the long-abandoned ruins of a decaying open source project repository. With some deciphering, we discover the the script is written in a primitive dialect of P#, the dominant language of the year 2051. It reads:

var a = 10;
var b = a + 1;
a = 11;
b = a + 1;

Through careful analysis of the script, we eventually decipher this to be an ancient parable. It tells the story of two brothers. a is the first born, proud and independent. b is the younger of the two, but it is dependent; it needs a. But the relationship is short lived. Once the second line is executed, and b grows up, the relationship between the adventurers ends - b is no longer dependent on a. When a changes, b does not. a must attempt to re-establish the once-lost relationship, but even that does not last.

We can relate to this as if it were the code version of Cats in the Cradle. First there is a, and b who needs a. But by the third line, b has grown up, and has no time for a. It is only when a calls that the two are momentarily re-connected, but even that is only fleeting.

Thanks to these cave paintings, we can draw the conclusion that the primitive compilers weren't smart enough to figure out that the destinies of these two proud brothers were intertwined. It seems that ancient programmers had to continually re-establish the relationship, or risk data being out of sync. As modern day code anthropologists, it's hard to imagine how it might have felt to write code like this.

In the year 2051, reactive programming is the norm. Language creators discovered the destiny operator decades ago, and the old ways were quickly forgotten. For example, in P#, we can write:

var a = 10;
var b <= a + 1;
a = 20;
Assert.AreEqual(21, b);

As you can see, the statement establishes b and a as having intertwined destinies, which are unbroken and forever. They are bound. The relationship between them isn't implicit, an idea that only exists in the mind of the programmers; it's explicit, a part of the language, and it exists for all time.

Although the destiny operator is wide spread, the way it works is a closely guarded secret. Some say that when the compiler encounters code that changes a, it inserts the corresponding change for b, such that they are always in sync. Others say that a, instead of being a lowly 4-byte integer, is ascended into a higher plane of existence. It becomes an observable, an object whose changes reverberate throughout the software at runtime, with the aid of event handlers created by the compiler. Old wives tales even tell of a great timer that constantly ticks, re-aligning all the variables after every change.

Nevertheless, through understanding the parable of the dependent brothers and getting a glimpse into the ways of ancient programmers, we can be even more thankful for the destiny operator and reactive programming. Instead of slaving over repetitive code and dealing with bugs, modern programmers can express relationships that last forever.

NB: P# is just the nickname for Microsoft Visual C#++Basic.NET on Rails, created by Paul Stovell in the year 2021

Back to: Magellan Home

Darren Neimke pointed me to Simone Chiaretta's useful reference of ASP.NET MVC extension points. Since Magellan's MVC Framework is inspired by ASP.NET MVC, I thought it would be useful reference to draw the connection between the extension points that Magellan supports and highlight some of the key differences.

#ASP.NET MVC Extension PointMagellan Implementation
1 RouteConstraint As Magellan does have the concept of user-visible URL's, routes and routing in general aren't required.
2 RouteHandler As above.
3 IControllerFactory IControllerFactory. Magellan also makes use of controllers, and controller factories manage their life cycle. Releasing works a little differently, but I'm hoping it's an improvement on the model. The documentation on controllers has more information, and there is also a sample on how to use them with IOC containers.
4 ActionInvoker IActionInvoker. Magellan controllers derived from the ControllerBase base class will defer to an IActionInvoker to call the action. The default implementation of IActionInvoker handles action and result filters, uses reflection to locate the methods, and generally works like the ASP.NET MVC equivalent. There is also an asynchronous version.
5 ActionMethodSelectorAttribute This isn't supported in Magellan, though I did consider it. It makes sense in ASP.NET MVC since you are dealing with HTTP requests and public URL's, and you may want to take other HTTP information into account (HTTP verbs are common). Since Magellan is in the rich client world, this isn't a consideration. Since not implementing this feature meant I could keep the implementation simpler, I didn't build it. If this is important, you can derive from the ActionInvoker base class and provide your own selection logic.
6 IAuthorizationFilter ASP.NET MVC draws a distinction between authorization filters and action filters, but the only real difference I've been able to see between them is authorization filters are invoked before action filters. I can think of few reasons why authorization couldn't be implemented with an action filter, so I just went with action filters in Magellan. I'm open to being convinced of why authorization filters should be added.
7 IActionFilter IActionFilter. Magellan supports action filters just like ASP.NET MVC, and they can do most of the same things. They can short-circuit the action, handle exceptions, change the return values, and so on.
8 IModelBinder IModelBinder. Magellan supports model binders too, and the default model binder is used for mapping parameters to actions. However, model binders in ASP.NET MVC exist because you often need to convert raw HTTP input into a rich object. Since Magellan exists in the rich client world, rich objects can be used natively, so I think it would be rare to use model binders. That said, they are supported.
9 ControllerBase ControllerBase and Controller. Controller is the most common base class, but you can derive from ControllerBase if you want to reuse the ActionInvoker usage without the friendly helpers Controller provides. You can also implement IController directly if you wish.
10 IResultFilter IResultFilter. Magellan also supports result filters. They can be used for changing the result, handling rendering exceptions, view reuse, and so on.
11 ActionResult ActionResult. Magellan uses action results as does ASP.NET MVC. The out-of-the-box results support views, cancellation, redirection, and a handful of other features. There's probably less use for custom action results in Magellan than in ASP.NET MVC, but they still come in handy.
12 IViewEngine IViewEngine. View engines are integral in locating and rendering views, so of course they are supported. Magellan ships with three out of the box - one for windows and dialogs, another for pages, and a third for Composite WPF support. I've also shown how to implement a view engine for Windows Forms.
13 HtmlHelper You can probably guess that this doesn't exist in Magellan. Magellan does provide a couple of useful extensions when writing views though, such as navigation behaviors and shared layouts.

Back to: Magellan Home

Rob Relyea might not like this, but today I had an idea.

When referencing controls from another assembly in XAML, one can either use xmlns:foo="clr-namespace:MyNamespace;assembly=MyAssembly" syntax, or a URI mapped with the XmlnsDefinition attribute. MSDN can tell you all about the attribute. Currently in Magellan I use it like this:

[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Abstractions")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Commands")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Behaviors")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Controls")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Framework")]
[assembly: XmlnsDefinition("http://xamlforge.com/magellan", "Magellan.Views")]

This allows you to reference any Magellan object with a simple reference:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:magellan="http://xamlforge.com/magellan" 
    >

The annoying thing about this, though, is you end up with ugly prefixes all over the XAML:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:magellan="http://xamlforge.com/magellan" 
    x:Class="Wizard.Views.Shared.Main" 
    >
    <DockPanel>
        <magellan:ZonePlaceHolder ZoneName="Left" DockPanel.Dock="Left" Width="300" />
        <magellan:ZonePlaceHolder ZoneName="Right" DockPanel.Dock="Right" Width="300" />
        <magellan:ZonePlaceHolder ZoneName="Content" />
    </DockPanel>
</UserControl>

Today I had an idea: I can usurp the Microsoft WPF XML namespaces by adding my own controls to them. It would be as simple as changing my XmlnsDefinition attrbutes to:

[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Abstractions")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Commands")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Behaviors")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Controls")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Framework")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Magellan.Views")]

Which lets me use this:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="Wizard.Views.Shared.Main" 
    >
    <DockPanel>
        <ZonePlaceHolder ZoneName="Left" DockPanel.Dock="Left" Width="300" />
        <ZonePlaceHolder ZoneName="Right" DockPanel.Dock="Right" Width="300" />
        <ZonePlaceHolder ZoneName="Content" />
    </DockPanel>
</UserControl>

Which not only reads nicer, but is also more accessible, since there's no need to manually add an import (ReSharper will add xmlns entries for you, but unfortunately it doesn't recognise XmlnsDefinition attributes).

My initial reaction is that this is evil, but in thinking about it, there are no Magellan classes that would conflict with classes in the WPF XML namespace. And if other libraries had the same names, you could use prefixes for those to differentiate, so that would just work. It also works fine in Blend. So the only problem that could arise is if someone else used this trick. But since it's so evil, I'd be the only one doing it, so there's no problem ;)

What do you think? Would you be disturbed by this, or would you actually find it a better experience?

Edit: It turns out that even if another library used this technique and was referenced, you can still differentiate between them by using an explicit xmlns:xyz reference. So I am not seeing much of a downside.

Back to: Magellan Home

When building WPF pages and windows, it's common to want a consistent layout across views. In ASP.NET, this is often accomplished with Master Pages. Magellan brings a similar concept to WPF, in the form of Shared Layouts.

The Magellan source code includes a new Wizard example application that demonstrates the shared layout feature. In this page I'll describe how it works.

The new Wizard sample

Creating and Using Shared Layouts

To create a shared layout, I typically add a Shared folder under Views:

A Visual Studio Project with a Shared folder containing Main.xaml, a shared layout, and a number of pages which use the layout

The shared layout, Main.xaml, is simply a UserControl with a number of ZonePlaceHolders. Each ZonePlaceHolder is given a Name, which we'll refer to later. The example below shows how a three-column layout might be declared. Since the layout is a UserControl, it can contain any XAML you wish:

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:magellan="http://xamlforge.com/magellan" 
    x:Class="Wizard.Views.Shared.Main" 
    >
    <DockPanel>
        <ZonePlaceHolder Name="Left" DockPanel.Dock="Left" Width="300" />
        <ZonePlaceHolder Name="Right" DockPanel.Dock="Right" Width="300" />
        <ZonePlaceHolder Name="Content" />
    </DockPanel>
</UserControl>

Now that our layout is declared, we can reference it from any other Window, Page or UserControl. Here's what a page might look like:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:magellan="http://xamlforge.com/magellan" 
    x:Class="Wizard.Views.Wizard.AccountDetailsPage" 
    Title="Account Details"
    >
    <Layout Source="/Wizard;component/Views/Shared/Main.xaml">
        <Zone ZonePlaceHolderName="Content">
            <TextBlock Text="The center content goes here" />
        </Zone>

        <Zone ZonePlaceHolderName="Left">
            <TextBlock Text="This content will appear on the left" />
        </Zone>

        <Zone ZonePlaceHolderName="Right">
            <TextBlock Text="This content will appear on the right" />
        </Zone>
    </Layout>
</Page>

The page uses the Layout control to reference the shared layout. The Source property is the URI to the the XAML file that contains the shared layout.

Composition

The Layout element is a control that takes a Source and a set of Zones. When it is loaded into the scene, it loads the shared layout user control and sets it as the content. Any ZonePlaceHolders inside the control will then have their content injected, based on the zone names matching.

The logical tree of the final page will look like this:

A diagram showing the logical tree of the page, layout and zones

Since the Layout is a child of the Page, this opens a number of possibilities:

  • The layout will inherit the DataContext of the page. If your DataContexts for each page have the same properties in common - such as using a shared View Model - the layout can make use of those.
  • The Layout can use WPF's Routed Events to communicate with the page.
  • The layout can use RelativeSource FindAncestor bindings to get properties from the page, such as the page title.

Default Zone Content

The ZonePlaceHolders are content controls, and their content is overridden when the layout is merged into the page, but only if the page specifies a corresponding zone. This means you can set default content for zones, and allow individual pages to override them.

For example, wizards often have a Back button. Using WPF Pages, the ZonePlaceHolder could be written as:

<ZonePlaceHolder Grid.Column="0" Name="BackNavigation">
    <Button Content="Back" Command="NavigationCommands.BrowseBack" />  
</ZonePlaceHolder>

If a page that refers to the layout doesn't specify a Zone with the same name, the back button will appear. But a page could override the content, for example:

<Zone ZonePlaceHolderName="BackNavigation"> 
    <Button Content="Cancel" Command="{Binding CancelWizardCommand}" />
</Zone>

Or it may just choose to clear the content, removing the button from the tree:

<Zone ZonePlaceHolderName="BackNavigation" Content="{x:Null}" />

Default Shared Layouts

Since the Layout control's Source property is a dependency property, you can use a Style to set the default layout source:

<Style TargetType="Layout">
    <Setter Property="Source" Value="/Wizard;component/Views/Shared/Main.xaml" />
</Style>

When writing pages, you can now just use a Layout element without a source:

<Layout>
    <Zone ZonePlaceHolderName="Content">
        <TextBlock Text="The center content goes here" />
    </Zone>

Or a page may choose to override the Layout:

<Layout Source="/Wizard;component/Views/Shared/Alternative.xaml">
    <Zone ZonePlaceHolderName="Content">
        <TextBlock Text="The center content goes here" />
    </Zone>

Interestingly, thanks to dependency properties, you could also use a Trigger or data binding to selectively change the layout based on user preferences.

Designer Support

Shared Layouts have good designer support with Expression Blend. For example, this is how the Main.xaml page from the Wizard example appears:

The Main.xaml file in Expression Blend

The individual pages that reference the shared layout also work in Blend:

A page in Blend that uses the shared layout

The only caveat to make it work in blend is that the URI must contain the assembly name of the layout. For example, this will work at runtime, but not design time:

<Layout Source="/Views/Shared/Main.xaml" />

However this will work at both design time and runtime:

<Layout Source="/Wizard;component/Views/Shared/Main.xaml" />

Nested Layouts

Nested layouts allow you to apply "inheritance" to layouts. For example, you can set up a common layout that provides a Title and Content zone. You can then create another layout that references the first layout, and sub-divides the content into two column, Left and Right. You might create another layout subdividing the two column layout even further - it's layouts all the way down.

A nested layouts example

Nested layouts are easy to create. First the Main.xaml:

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:magellan="http://xamlforge.com/magellan"
    >
    <DockPanel>
        <ZonePlaceHolder Name="Title" DockPanel.Dock="Top" />
        <ZonePlaceHolder Name="Content" />
    </DockPanel>
</UserControl>

Now the TwoColumn.xaml, which references Main.xaml:

<UserControl 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:magellan="http://xamlforge.com/magellan"
    >

    <Layout Source="/MyAssembly;component/Layouts/Main.xaml">        
        <Zone ZonePlaceHolderName="Title">
            <ZonePlaceHolder Name="Title" />
        </Zone>

        <Zone ZonePlaceHolderName="Content">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <ZonePlaceHolder Grid.Column="0" Name="Left" />
                <ZonePlaceHolder Grid.Column="1" Name="Right" />
            </Grid>
        </Zone>
    </Layout>
</UserControl>

Note how this layout references the first. To re-expose the Title zone, we create a Zone with a ZonePlaceHolder. We also expose a Left and Right zone by splitting the Content zone using a Grid.

Summary

Shared Layouts allow you create a consistent look and feel for your views while minimizing XAML and code behind. They can be used not only on Pages, but from any XAML - you might create a Shared Layout for Dialogs with OK/Cancel buttons, or for tab pages within an options dialog.

To make use of shared layouts, you just need a reference to Magellan.dll. You don't have to use Magellan's MVC framework to use this feature, as they are completely independent.

I'd love any feedback on how to make this feature more useful.

Back to: Magellan Home