MVP In Silverlight/WPF: The Sample

20 commentsWritten on August 3rd, 2010 by
Categories: MVP In Silverlight/WPF

Note: This post is part of a series. You can find the introduction and overview of the series here.

Coming up with a good sample project for this series wasn't easy. It had to be small enough to be easy to comprehend and look into, yet it also has to make it clear why i prefer the MVP approach over the MVVM approach, which isn't easy to do when you have a very simple sample. There has to be business logic, and it has to be encapsulated by a Service Layer. But i obviously wanted to avoid having to use a database and go through everything to get all of that working while still being easy to download and play around with it. The Service Layer has been implemented very quickly, and is not representative of a real Service Layer. It doesn't use a database, it holds its data statically in memory (and doesn't even care about thread-safety of this data either) and i didn't even write tests for any of it. It's just a simple Service Layer, implemented with a Request/Response Service Layer. It accepts Requests and returns Responses with DTO's (not entities obviously) to the client. That's it.

The client code has been written entirely using Test Driven Development. Apart from the Views, everything is tested and the tests are obviously also included in the downloadable Visual Studio solution. Some tests were written after a piece of code was written, but most of the tests were written before the actual code was written. I hope you go through the tests to see just how much UI logic you can actually cover quite easily. I also hope you'll notice that the large majority of tests is very short and focused, which would be harder to achieve when using MVVM. If you have questions regarding the implementation of the User Controls or their tests, it might be better to hold off on asking them until i've published the posts that cover writing the implementations and the actual tests. You can always ask questions if you want of course, but odds are high that i'm gonna cover the answer to your question in one of the future posts anyway.

One more important thing: the client in this sample is Silverlight, not WPF. You can apply all of these ideas to WPF programming as well obviously.

Now, what exactly is the sample project about? Here's a screenshot:

You're probably laughing pretty hard at my lousy UI skills (and rightfully so), but i'm sure you'll agree that the crappy looking UI is not relevant to the topic we're covering in this series ;)

That screenshot shows 2 UserControls. The implementation of both UserControls will be covered in-depth in the next 2 posts in this series, but for now, i'm just going to tell you what they're supposed to do.

The first UserControl looks like this:

It has a TreeView which shows a UserGroup hierarchy. When you select a UserGroup, its details must be displayed in the second UserControl where they can be edited. There's also a button to create a new UserGroup, whose details must also be provided in the second UserControl. Finally, when a UserGroup has been modified (or deleted) in the second UserControl, the contents of the TreeView must be updated correctly without simply fetching the entire hierarchy again.

The second UserControl looks like this:

In this UserControl, you can modify the name of the UserGroup, change its Parent, or just delete the UserGroup. If you've made changes, but haven't pushed the Save button yet, you can press the Cancel button and the values will be reverted to their original values. If you make a change here, the TreeView in the first UserControl needs to be updated to reflect that change (either an updated name, or a different parent).

In both UserControls, some of the actions that the user can perform are either enabled or disabled based on the permissions of the user. Right now, the permissions can only be changed in the code, but feel free to do so to see how that works.

Initially, i wanted to add a third UserControl where you can add/remove Users to the selected UserGroup. While you'll find some traces of this in the Service Layer code, there is nothing in the client to do this. Feel free to try to implement such a UserControl to see whether or not you like this whole approach with some hands-on coding.

I hope you'll find the sample to be small enough, but still have enough 'complexity' to show the benefits of using the MVP pattern over MVVM. Also, keep in mind that this sample is not perfect and that there are still some bugs in it. If you want to criticize, please focus on problems that are inherent to the usage of MVP instead of MVVM since that's what this is all about.

You can download the sample here.

In the next 2 posts, we'll cover the implementation of both UserControls in their entirety, and after that we'll focus on automated tests.

  • Brevin

    do you use vs2010? can not open it with vs2008. seems I need find a new version for this

    • http://davybrion.com Davy Brion

      Yeah sorry. It’s vs2010, .net 4 and silverlight 4

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #657

  • Mjelten

    I have been working with the MVP pattern for a while and started with MVVM for a year ago. I really like the approach of getting the binding features into the MVP pattern. Thank you!

  • Alex Simkin

    Davy,

    How would you change your sample so that if more than one client work with the data they all could see changes made by each other? Include all changed entities in service responce?

  • http://davybrion.com Davy Brion

    @Alex

    if they all need to see every change by other users immediately, i’d probably use a duplex binding and push the changes to all the clients… it’s an approach i would strongly prefer to avoid though

    including other people’s changes in responses is not something i’d do either, because then you’d need to keep track of which changes have been sent to each user, and there’s still the issue of an unpredictable delay with regards to when you’ll see the ‘latest’ data

    so it basically depends on what the user wants: do they want the treeview to update itself automatically every so often? If so, they should decide on what they want to see happening if they’re currently updating something, how to deal with the currently selected item (if it no longer exists or something like that) and other issues like that

    In a lot of cases, a simple refresh button turns out to be the preferred solution

  • Alex Simkin

    @Davy,

    Thank you for your responce.

    The other question: Is View-first approach is something inherent to your pattern or Presenter-first will do as well?

  • http://davybrion.com Davy Brion

    @Alex

    in my particular approach, it’s always View-first because of what i said in the infrastructural bits post:

    “Another possibility would’ve been for the IOC container to instantiate the View, pass it to the Presenter since it’s a constructor dependency and then let the Presenter pass itself to the View, but then you lose the ability to simply use your User Controls in the XAML of other User Controls. So for those reasons, the View is not instantiated by the IOC container, and you are required to resolve your own Presenter reference in your View.”

    obviously, there’s nothing really that prevents you from doing Presenter-first, though not being able to simply use your view in the XAML of another user control is something that i don’t really like. unless there’s a way to do Presenter-first while still being able to use the View in another UserContro’s XAML that i just haven’t ran into or figured out yet :)

  • Alex Simkin

    Passing View to Presenter’s constructor will make testing awkward. I was thinking about creating View and Presenter separately and then connecting them using some convention based binder (al la Rob Eisenberg’s one). This will probably eliminate some code behind.

  • http://davybrion.com Davy Brion

    @Alex

    why does it make testing awkward? i want to be able to test the interaction between the presenter and the view, so the fact that i can inject a mocked view into the presenter is a huge benefit to me

    you can look at the presenter tests in the sample to see what i mean

    “This will probably eliminate some code behind.”

    As you’ll read in my next post, i really don’t think there’s anything wrong with a bit of code-behind code as long as it only contains View-related stuff.

  • Alex Simkin

    “i can inject a mocked view into the presenter is a huge benefit to me”

    The only thing that makes me a little uncomfortable is that Presenter knows too much about View. Having methods like

    SelectItemInTreeView;
    ExpandTreeView();

    doesn’t seem right. What if designer decides to ditch tree view and replace it with some other control? The view should be controlled by binding model only.

  • http://davybrion.com Davy Brion

    @Alex

    “The view should be controlled by binding model only.”

    i think both are fine… a very large majority of developers simply doesn’t work with designers who are in charge of the actual View so i wouldn’t get too hung up on that

  • Mjelten

    Thank you for you posts, very good. I just want to agree with Alex, when building the interface i think that the names of methods should be more unspecific. Instead of ExpandTreeView, it could be something like ShowAllUserGroupsAndItsChildrens(). Then it will be up to the view to determine how do it.

  • http://davybrion.com Davy Brion

    @Mjelten

    agreed, the names of those methods could definitely be more control-agnostic :)

  • Mjelten

    You want to be able to build a new view without changing the presenter and the interface of the View. Maybe you are on a diffrent platform, say a tablet PC, and a treeView might not fit your purpuse.

  • bennyb

    There seems to be a stackoverflow:

    in the view constructor for UserGroups you call the CreateAndInitializePresenter

    public UserGroups()
    {
    InitializeComponent();
    presenter = CreateAndInitializePresenter();
    }

    But the presenter constructor needs an instance of IUserGroupsView. This in tends calls the UserGroups() constructor again, which calls the CreateAndInitializePresenter again.

  • bennyb

    Got it. Will have to modify Agatha.Ninject to use the dictionary in “Resolve”

    IoC.Container.Resolve(new Dictionary { { “view”, this } });

  • bennyb

    How do you add KnownTypes

  • http://davybrion.com Davy Brion

    @Bennyb

    you don’t have to modify Agatha for that… just pass your container instance to Agatha, and use the same instance as you’d normally would to register your types

    as for adding types to the KnownTypeProvider: just call the RegisterDerivedTypesOf method, as discussed here: http://davybrion.com/blog/2008/07/the-known-type-provider/

  • bennyb

    Cool. I ended up doing this:

    presenter = CreateAndInitializePresenter<UserGroupDetailPresenter, IUserGroupDetailsView>();

    and in the method I use

    protected TPresenter CreateAndInitializePresenter<TPresenter, TViewInterface>() where TPresenter : class, IPresenter
    {
    if (inDesignMode)
    {
    return default(TPresenter);
    }

    IoC.Container.RegisterInstance(typeof(TViewInterface), this);
    TPresenter p = IoC.Container.Resolve<TPresenter>();// (new Dictionary { { “view”, this } });
    p.Initialize();
    DataContext = p.GetBindingModel();
    presenter = p;
    return p;

    }

    Thanks!