preload
Mar 31

I am very fond of using patterns when developing and I have seen the importance of patterns in several projects. When it comes to Windows Phone 7 development I guess the most popular pattern to use is the Model-View-ViewModel (MVVM) pattern. I have successfully used a different (but still quite similar) pattern for several mobile app projects. In this post I will show you how to use the Model-View-Presenter (MVP) pattern when developing Windows Phone 7 applications.

I will not go into details describing the MVP-pattern since I covered that pretty well in another post I wrote a while back: Using Model-View-Presenter (MVP) pattern in Compact Framework. What I will do is to show an example on how you can design your Windows Phone 7 app architecture to use MVP-pattern. I will use the same login example as I used in the Compact Framework post. You can see that the biggest difference between how you do this for CF and WP7 is the data binding capability in WP7.

Before we go to the code a short summary on the essence of the MVP-pattern: The View is only responsible for displaying output to the user and receiving input from the user. The View will always ask the Presenter what to do with the data and the Presenter will pass the data on to the View. The Model consists of business objects and can be used both by the Presenter and the View. The figure below explains the MVP-pattern.

Now it’s time to have a look at the code. For this example I have created a solution called MvpDemo. To this solution I have added two projects. One Silverlight for Windows Phone – Windows Phone Application project called MvpDemo and one Silverlight for Windows Phone – Windows Phone Class Library called MvpDemo.MVP.

Within the MvpDemo.MVP project I created the following folders: “Model”, “View” and “Presenter”. In the Presenter folder I create a folder called Interface and in the View folder I create the folders Interface and Data. The Interface folders are just to make the project structure more clearly since I have an interface for each View and Presenter class.

First I create the interface for LoginView defining the methods the LoginView must implement, these methods will be called by the LoginPresenter. The InitializeView method is used by the Presenter to initialize the view passing on the ViewData (will be used for data binding). The LoginUserCompleted method is used by the Presenter to notify the view when login is completed. Below you can see my ILoginView.cs class

using MvpDemo.MVP.View.Data;

namespace MvpDemo.MVP.View.Interface
{
    public interface ILoginView
    {
        void InitializeView(LoginViewData viewModel);
        void LoginUserCompleted(string result);
    }
}

Then I create the interface for LoginPresenter defining the methods the LoginPresenter must implement, these methods will be called by the View. The InitializeView method is used by the LoginView to notify the Presenter that the View is ready to receive data to display (if any). The LoginUser method is used by the View when the user presses the login button. Note that the View don’t have to pass username and password to the Presenter due to the data binding (will get back to this). Below you can see my ILoginPresenter.cs class

namespace MvpDemo.MVP.Presenter.Interface
{
    public interface ILoginPresenter
    {
        void InitializeView();
        void LoginUser();

    }
}

Lets have a look at the LoginViewData. The Presenter is responsible for sending the LoginViewData to the LoginView and the LoginView will set the LoginViewData as DataContext and bind its controls to the data fields. I have implemented INotifyPropertyChanged so a PropertyChanged event will be fired when data fields changes and the view can be updated. Below is my LoginViewData.cs class

using System.ComponentModel;

namespace MvpDemo.MVP.View.Data
{
    public class LoginViewData : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _userName = string.Empty;
        private string _password = string.Empty;
        private bool _rememberMe;

        public string UserName
        {
            get { return _userName; }
            set
            {
                _userName = value;
                RaisePropertyChanged("UserName");
            }
        }

        public string Password
        {
            get { return _password; }
            set
            {
                _password = value;
                RaisePropertyChanged("Password");
            }
        }

        public bool RememberMe
        {
            get { return _rememberMe; }
            set
            {
                _rememberMe = value;
                RaisePropertyChanged("RememberMe");
            }
        }

        public void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

The last class we are going to add in the MvpDemo.MVP project is the LoginPresenter. The LoginPresenter implements the ILoginPresenter and is constructed by the view with the view interface. When the view calls the InitializeView method the Presenter will create the LoginViewData and pass this on to the view. I am also assuming that we have a WCF service reference in the project and the Presenter is using the service to perform login. When the service is completed with the login the Presenter will be notified by the ServiceLoginUserCompleted method and the Presenter will notify the View. If login was successful the Presenter will pass the user name to the View and null if not. If you want to learn about WCF, SQL Azure and Cloud for WP7 you can read a post I wrote about that subject earlier: How to use WCF service to access SQL Azure Database from Windows Phone 7. Below you can see my LoginPresenter.cs class

using MvpDemo.MVP.Service;
using MvpDemo.MVP.Presenter.Interface;
using MvpDemo.MVP.View.Data;
using MvpDemo.MVP.View.Interface;

namespace MvpDemo.MVP.Presenter
{
    public class LoginPresenter : ILoginPresenter
    {
        private readonly ILoginView _view;
        private LoginViewData _viewModel;
        private readonly Service1Client _service;

        public LoginPresenter(ILoginView view)
	    {
	        _view = view;
            _service = new Service1Client();
            _service.LoginUserCompleted += ServiceLoginUserCompleted;
	    }

        public void InitializeView()
        {
            _viewModel = new LoginViewData();
            _view.InitializeView(_viewModel);
        }

        public void LoginUser()
        {
            _service.LoginUserAsync(_viewModel.UserName, _viewModel.Password);
        }

        private void ServiceLoginUserCompleted(object senter, LoginUserCompletedEventArgs e)
        {
            if (e.Error == null && e.Result != null)
            {
                _view.LoginUserCompleted(e.Result);
            }
            else
            {
                _view.LoginUserCompleted(null);
            }
        }
    }
}

Now we are going to create the LoginView in our MvpDemo project. I create a folder called “Views” and add a new Windows Phone Portrait Page which I call LoginView. In the LoginView.xaml file I create a very simple GUI where the user can enter user name, password, if the login should be remembered and select login. Notice how I use data binding to bind UserName, Password and RememberMe with the LoginViewData. Below you can see a screen shot of what the app will look like.

This is my LoginView.xaml file that will generate the GUI above.

<phone:PhoneApplicationPage
    x:Class="MvpDemo.Views.LoginView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="MVP-pattern example" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="Login" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" TextAlignment="Center" />
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBox Height="72" HorizontalAlignment="Left" Margin="29,74,0,0" Name="userNameTxtBox" Text="{Binding Path=UserName, Mode=TwoWay}" VerticalAlignment="Top" Width="400" />
            <TextBlock Name="txtUsername" Style="{StaticResource PhoneTextNormalStyle}" Text="User name" Margin="46,38,41,529" FontSize="26" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="28,181,0,0" Name="passwordTxtBox" Text="{Binding Path=Password, Mode=TwoWay}" VerticalAlignment="Top" Width="400" />
            <TextBlock FontSize="26" Margin="45,145,42,422" Name="txtPassword" Style="{StaticResource PhoneTextNormalStyle}" Text="Password" />
            <Button Content="Login" Height="72" HorizontalAlignment="Left" Margin="185,336,0,0" Name="loginBtn" VerticalAlignment="Top" Width="243" Click="LoginBtnClick" />
            <CheckBox Content="Remember me" Height="72" HorizontalAlignment="Left" Margin="30,245,0,0" Name="rememberMeChkBox" VerticalAlignment="Top" IsChecked="{Binding Path=RememberMe, Mode=TwoWay}" />
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>

The last class we need to add some code in now is the LoginView.xaml.cs. The LoginView is implementing the ILoginView and creating the LoginPresenter when the view is loaded. The view asks the presenter for data. The LoginView sets the LoginViewData (received from the presenter) as DataContext, to ensure data binding.  When the results from LoginUserCompleted arrives from the presenter the LoginView will display the user name if login succeeded or an error message if login failed. Below you can see my LoginView.xaml.cs class

using System;
using System.Windows;
using MvpDemo.MVP.Presenter;
using MvpDemo.MVP.View.Data;
using MvpDemo.MVP.View.Interface;

namespace MvpDemo.Views
{
    public partial class LoginView : ILoginView
    {
        private LoginPresenter _presenter;

        public LoginView()
        {
            InitializeComponent();
            Loaded += LoginViewLoaded;
        }

        void LoginViewLoaded(object sender, RoutedEventArgs e)
        {
            if (_presenter != null) return;
            _presenter = new LoginPresenter(this);
            _presenter.InitializeView();
        }

        public void InitializeView(LoginViewData viewModel)
        {
            DataContext = viewModel;
        }

        public void LoginUserCompleted(string result)
        {
            if (result != null)
            {
                MessageBox.Show("Welcome " + result + "!");
            }else
            {
                MessageBox.Show("Could not log in. Please check user name/password and try again.");
            }
        }

        private void LoginBtnClick(object sender, RoutedEventArgs e)
        {
            _presenter.LoginUser();
        }
    }
}

That’s it! You now have a Windows Phone 7 project using the MVP-pattern. I like this pattern because it is very clear, the code readability is good, separation of code and responsibility is well taken care of.

Follow me on twitter @PerOla

Share & enjoy
You can subscribe to my comments feed to keep track of new comments.

4 Comments to “Using Model-View-Presenter (MVP) pattern in Windows Phone 7 projects”

  1. Jeff says:

    Great article. Thanks for taking the time. I have always been a huge MVC/MVP proponent. However, over the past few months, I have been trying to make the move to MVVM. Now you have got me thinking. Do you use MVP with WPF and Silverlight?

  2. Hi Jeff, I’m glad you liked the article.
    I have only used the MVP-pattern for Windows Phone and Windows Mobile projects.

  3. Brendan says:

    Its good to see more articles using MVP on WindowsPhone.
    Code looks very similar to using http://windowsphonemvp.codeplex.com/

  4. Hi Brendan,
    I think it’s important to show that it’s not only MVVM that can be used for Windows Phone projects. I have been using the MVP pattern for several projects so I did not want to change over to MVVM.
    I have not seen the project on codeplex before, looks quite similar.

5 Pingbacks to “Using Model-View-Presenter (MVP) pattern in Windows Phone 7 projects”

  1. […] I guess the most popular pattern to use is the Model-View-ViewModel (MVVM) pattern. I have… [full post] Per Ola Sæther breathingtech.com – Blog about Technology, Mobility and Software Development […]

  2. […] Using Model-View-Presenter (MVP) pattern in Windows Phone 7 projects (Per Ola Sæther) […]

  3. […] You might also be interested in reading how to use the Model-View-Presenter pattern in Windows Phone 7 projects. […]

  4. […] now know enough to decide how the application architecture will be. I will use the Model-View-Presenter (MVP) pattern and I will have a utilization class for storing and retrieving data from the isolated […]

  5. […] of the sketching and analyses I did earlier for the PinCodeKeeper I know that I will be using the Model-View-Presenter (MVP) pattern and I know what views (screens) I will be using. Therefore I start by adding some folders to my […]

Leave a Reply

Subscribe to my comments feed

Subscribe to my feeds Follow me on Twitter
DZone MVB