Magellan Introduction

Back to: Magellan Home

Magellan is a lightweight framework that makes it easy to build WPF navigation applications. It is inspired by the ASP.NET MVC framework. The main features are:

  • Model-View-Controller support
  • Action filters for cross-cutting concerns such as authorization and redirection
  • Blend behaviors to make navigation easy
  • Transitions between pages

Magellan was drawn from a number of samples I had put together early this year and some work done on a client project.

The source download includes an "iPhone" application for demonstrating the features.

The sample iPhone application

We start with a simple project structure:

A VS2008 project with a number of folders for controllers, models and views

A controller implementation typically looks like this:

public class PhoneController : Controller
{
    public ActionResult Group(Group group)
    {
        var contacts = _contactRepository.GetContacts(group);

        Model = new GroupViewModel(group.Name, contacts);
        return Page();
    }

Views are XAML Page objects, and can optionally have a model. Here's an example:

View models

The idea is that upon navigation, a controller is created, the action is executed, and the view and view model are created. The view then becomes the focus of the frame. Put simply, the view and viewmodel are stateful, and the controller is stateless.

Navigation between views (with nice transitions) can be done either programatically:

Navigator.For(Frame).NavigateWithTransition("Home", "Main", "ZoomOut");

Or through Blend behaviors:

Blend Navigate behavior

The framework supports the ASP.NET MVC concepts of Action Filters, Model Binders, View Engines and more - I'll cover them in a later post.

Back to: Magellan Home

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.

25 Oct 2009

Paul

Having just read a book on ASP MVC, this looks quite interesting. I could not see how the Model/ViewModel got associated with the View. But I like the idea a lot

25 Oct 2009

Aha that is actually done in the Render method, nice one

25 Oct 2009

Very. Cool.

26 Oct 2009

Look good!

Didn't Magellan die on the way!

26 Oct 2009

Looks good! I've never really liked how MVVM manages navigation, so this can be great.

30 Oct 2009

Do you think this can handle a more LOB desktop app, where you can have several windows (or views) open at the same time?

Example, you go and start editing a contact, then you have to go to look for something else, but you're not finished with the editing. How do think Magellan could handle this?

30 Oct 2009

Hi Eduardo,

The latest code has some integration with the Composite WPF library (Prism).

Navigation is scoped to a navigation service, and can also be executed without a navigation service. Your controllers can return:

  • Pages (which will be shown in a navigation service)
  • Windows (which will be shown as a new window/dialog)
  • Views (which can be shown in a Prism 'region')

So when a contact is opened, one controller action would return an action result to the effect of "create a new Contact view, and show it in the Content region". Your Prism region adapter would add the item to a tab control. This way, you can have multiple objects open at once.

Now, within a tab, you might choose to have navigation frames. So one tab could be "pay bill". Within that tab you would navigate through the process of paying a bill, but you can have other tabs open with different tasks.

Once I flesh out some of the Prism integration I'll extend the sample applications to demonstrate this and write some more posts on it.

Paul

30 Oct 2009

Thanks Paul. After writing the comment I was thinking about letting the user to have more frames (in the main window), so they can have multiple views at once, yet retaining the simpler web style navigation of your framework.

05 Nov 2009

Three things:

  1. Download and install KB958017 RollUp Hotfix for VS2008 if you want fix the pesky warning about Blend Interaction behaviors. http://code.msdn.microsoft.com/KB958017/Release/ProjectReleases.aspx?ReleaseId=1719

  2. Paul: Where do you think is the right place to ask questions about Magellan? StackOverflow?

  3. Do you know that http://magellan-project.org/ (used in your code) is taken a SAP product?

05 Nov 2009

Paul: Suppose that you are editing a contact.
You have the Save button with

        <Button Content="Save" IsEnabled="{Binding CanSave}">
            <i:Interaction.Behaviors>
                <magellan:NavigateBehavior Action="Save" Controller="Contact" Transition="Forward">
                    <magellan:NavigateBehavior.Parameters>
                        <magellan:Parameter ParameterName="Contact" Value="{Binding Path=SelectedItem}"/>
                    </magellan:NavigateBehavior.Parameters>
                </magellan:NavigateBehavior>
            </i:Interaction.Behaviors>
        </Button>

How do I code the controller side of this?

Public Function Save(ByVal Contact As Contact) As ActionResult
    Try
        Contact.Save() 'perform the DB saving
        Return Index() 'Call other action result that brings the list of contacts?
    Catch ex As Exception
        'what to do here? return a dialog window? I tried but only ActionResult allowed
        'Even if I managed to warn the user about the error, how to return a "DoNothing" result?
    End Try
End Function

Maybe I'm expecting too much from the project, and have to mix it with regular WPF to do a real world app. You tell me.

05 Nov 2009

@Eduardo: you're welcome to use StackOverflow or just post them as questions on this blog. I'll set up a bug tracker soon. I'll check the magellan name issue with the domain owner.

To make your example work, get the latest Magellan build. There are two view engines by default - one for pages and one for Windows. The second one will detect that your view is a window, and call Window.Show(). I plan to have an attribute or interface that allows the view to decide whether to be shown as a dialog or normal window, but if you like you can write your own ViewEngine (start with the WindowViewEngine).

Your controller in that example would look something like this:

Public Function Save(ByVal Contact As Contact) As ActionResult
    Try
        Contact.Save() 'perform the DB saving
        Return Index() 'Call other action result that brings the list of contacts?
    Catch ex As Exception
        return View("Error")
    End Try
End Function

In your project you could add an ErrorWindow.xaml which is just a regular Window (optionally implementing IView if you want to make use of a model). The ViewEngine will detect that it is a Window and will show it.

To answer your second question - how to tell it to do nothing - you can return a CancelResult like this:

Public Function Save(ByVal Contact As Contact) As ActionResult
    Try
        Contact.Save() 'perform the DB saving
        Return Index() 'Call other action result that brings the list of contacts?
    Catch ex As Exception
        exceptionHandler.HandleException(ex)
        return New CancelResult()
    End Try
End Function

You can see how the Cancel action result is implemented here.

(I meant to add a convenience method to Controller to make this easy - i.e., return Cancel() - I'll check that in tonight.

06 Nov 2009

Hi Paul, it's me again :)

When you have this method in the controller

Public Function Save(ByVal Contact As Contact) As ActionResult
    Try
        Contact.Save() 'perform the DB saving
        Return Index() 'Call other action result that brings the list of contacts
    Catch ex As Exception
        return View("Error")
    End Try
End Function
  1. Is there a way that Index does not create another view, but navigate to the existing one (if exists)?
  2. Is there a way to destroy a View (in this case, the contact view, which is not longer valid because the record is already saved in the DB)

Thanks again!

08 Nov 2009

This is awesome! I can definitely see how this will make things easier for developers coming from ASP.NET MVC (like me). Fantastic job so far! :)

25 Nov 2009

I've reposted the question in StackOveflow. http://stackoverflow.com/questions/1797307/wpf-magellan-is-there-a-way-to-navigate-to-a-existing-view