My notes on approaching a proper MVVM WP7 phone app

First, I’m an idiot. I wrote a whole application based on an idea – and saved the “simple” part of the idea for the end – but it turns out, I can’t do the simple part on Windows Phone 7!

The idea was simple, make a little app that lets you set up a list of machines to ping – called Mobile Ping. From the main page you could see the list of servers and a little colored icon that would show the status. The good news is, the whole app is functional – except there is no way to actually “ping” from WP7. This was shocking because you can even ping from the .NET Micro framework, and I would’ve thought a WP7 phone is a more advanced device?

Anyhow – with all that said, I learned a lot of things along the way. First, per Binoj’s recommendation (see: it2max.com) I picked up 101 Windows Phone 7 Apps: Volume I – which is an absolute essential for any WP7 developer. I mean, this is the biggest single resource I’ve found – it’s hugely helpful.

The things in this post are for WP7, but a vast majority of this is completely compatible with regular Silverlight and WPF. Only the Phone-specific API’s are specific to WP7. So, below are some of the basic questions I got answers to:

Project Layout for MVVM:
To know me, is to know how much I really like Model-View-ViewModel pattern for WPF, Silverlight, and WP7. This design pattern truly is a thing of beauty. So, I of course approached this app, using this pattern – which led me to a layout like the following:

image

Models – represents data structures (classes that hold data in properties), including collections. Support – represents a namespace where I can put unrelated support and utility classes. ViewModels – represents where I can put ViewModels that are consumed by the Views. Views – represents where User Control ‘Views’ can be placed, and are consumed from the main pages – in the root. Images are where the app images go, and Icons is where the app bar icons go.

A base class for MVVM on WP7:
MVVM is based on the notion of data binding and the UI being “notified” when a property or collection has changed. That’s great, but it does require a tiny bit of code to support this. So, I ended up evolving a base class that has this core functionality. It includes a helper method for INotifyPropertyChanged.PropertyChanged – as well as pre-wired event handlers for app startup, shutdown, etc.

    /// <summary>

    /// Abstract class that supports application events, and that handles the <see cref=”INotifyPropertyChanged”/> interface event.

    /// </summary>

    public abstract class ApplicationSupportBase : INotifyPropertyChanged

    {

        /// <summary>

        /// When chained from a concrete class, properly initializes the events and startup facilities for this type.

        /// </summary>

        protected ApplicationSupportBase()

        {

            if (PhoneApplicationService.Current != null)

            {

                PhoneApplicationService.Current.Activated += new EventHandler<ActivatedEventArgs>(OnApplicationActivated);

                PhoneApplicationService.Current.Closing += new EventHandler<ClosingEventArgs>(OnApplicationClosing);

                PhoneApplicationService.Current.Deactivated += new EventHandler<DeactivatedEventArgs>(OnApplicationDeactivated);

                PhoneApplicationService.Current.Launching += new EventHandler<LaunchingEventArgs>(OnApplicationLaunching);

            }

 

            System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged +=

                new System.Net.NetworkInformation.NetworkAddressChangedEventHandler(OnNetworkAddressChanged);

        }

 

        /// <summary>

        /// Event for when a property has changed.

        /// </summary>

        public event PropertyChangedEventHandler PropertyChanged;

 

        /// <summary>

        /// Event handler for when the application is closing.

        /// </summary>

        protected virtual void OnApplicationClosing(object sender, ClosingEventArgs e)

        {

        }

 

        /// <summary>

        /// Event handler for when the application is launching.

        /// </summary>

        protected virtual void OnApplicationLaunching(object sender, LaunchingEventArgs e)

        {

        }

 

        /// <summary>

        /// Event handler for when the application is deactivated.

        /// </summary>

        protected virtual void OnApplicationDeactivated(object sender, DeactivatedEventArgs e)

        {

        }

 

        /// <summary>

        /// Event handler for when the application is activated.

        /// </summary>

        protected virtual void OnApplicationActivated(object sender, ActivatedEventArgs e)

        {

        }

 

        /// <summary>

        /// Event handler for when the network address has changed.

        /// </summary>

        protected virtual void OnNetworkAddressChanged(object sender, EventArgs e)

        {

        }

 

        /// <summary>

        /// Raises the <see cref=”PropertyChanged”/> event for the specified <paramref name=”propertyName”/>.

        /// </summary>

        /// <param name=”propertyName”>The name of the property that has just been updated.</param>

        /// <exception cref=”ArgumentException”>When <paramref name=”propertyName”/> is null or empty.</exception>

        protected virtual void RaisePropertyChanged(string propertyName)

        {

            if (string.IsNullOrEmpty(propertyName))

                throw new ArgumentException(“Argument ‘propertyName’ cannot be null or empty.”);

 

            if (PropertyChanged != null)

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

        }

    }

 

What this means is that models, viewmodels, or anything else can just inherit from this abstract class and automatically have RaisePropertyChanged() and these other handlers.

MVVM and INotifyChangedEvent and ObservableCollection<T>:
Now again, MVVM is based on the idea of data binding and being notified of when a property or collection has changed. How do you do that exactly? And how is is different from how I might normally code?

For regular properties, instead of doing something like this:

/// <summary>

/// Gets or sets the fully-qualified-domain-name (FQDN) of the server.

/// </summary>

/// <exception cref=”InvalidOperationException”>When an attempt is made to set this property to null or empty.</exception>

public string FullName

{

    get { return fullName; }

    set

    {

        if (string.IsNullOrEmpty(value))

            throw new InvalidOperationException(“Property ‘FullName’ cannot be set to null or empty.”);

 

        fullName = value;

    }

} string fullName = “(Unknown)”;

 

you would do something like this:

/// <summary>

/// Gets or sets the fully-qualified-domain-name (FQDN) of the server.

/// </summary>

/// <exception cref=”InvalidOperationException”>When an attempt is made to set this property to null or empty.</exception>

public string FullName

{

    get { return fullName; }

    set

    {

        if (string.IsNullOrEmpty(value))

            throw new InvalidOperationException(“Property ‘FullName’ cannot be set to null or empty.”);

 

        fullName = value;

        RaisePropertyChanged(“FullName”);

    }

} string fullName = “(Unknown)”;

 

Note that in the setter, I’m calling that RaisePropertyChanged method – which fires that event. When you databind from WPF, Silverlight, etc – those controls automatically wire up and look for that event. So, when you change a property in code, the UI is automagically updated.

Now, you might notice that this technique does not work the same for collections. Luckily they thought of that. There is a special class called ObservableCollection<T> in System.Collection.ObjectModel. This is a special kind of collection, that basically does the same thing – whenever items are added or removed from the collection.

So, in your application, if you need do this – I simply create a new type, to nicely wrap this functionality, for example:

/// <summary>

/// Observable collection of <see cref=”ServerPingDetail”/> objects.

/// </summary>

public class ServerPingDetailCollection : ObservableCollection<ServerPingDetail>

{

    /// <summary>

    /// Creates a new instance of this type.

    /// </summary>

    public ServerPingDetailCollection()

        : base()

    {

    }

}

 

Now, when I bind a listbox or something to it, the UI automatically updates when I add/remove items from this collection. Speaking of which – how DO you expose these bind-aware items to the UI? With a ViewModel.

Setting up the ViewModel:
OK, so we have some data structures in the Models folder, they implement INotifyPropertyChanged or inherit from ObservableCollection<T>. Now, we need to present a data structure for the UI to bind to, this is the ViewModel. The purpose of the ViewModel is to expose a single interface of everything that a view will need. So collections, properties, etc that a view needs, should be exposed in one ViewModel. In this case, I have several views which happen to need the same data, so I just have one ViewModel – but you very well would typically have several ViewModels and several Views. It’s like a one-to-many relationship: a View uses exactly one ViewModel, but a ViewModel might be used by several views.

So, here is what the main ViewModel looks like:

    /// <summary>

    /// ViewModel for the UI which presents the core information for this application.

    /// </summary>

    public class SummaryViewModel : ApplicationSupportBase

    {

        /// <summary>

        /// Creates a new instance of this type.

        /// </summary>

        public SummaryViewModel()

            : base()

        {

            NetworkStatusText = “Loading…”;

 

            try

            {

                // Load the current users settings

                Load();

            }

            catch (IsolatedStorageException)

            {

                // BUG: I keep getting errors in the designer, even though I’m catching this in the ViewModel

                // I need to figure out why the designer is letting this exception slip by in the other class,

                // but it DOES catch it here. Weird.

            }

 

 

            // Update the UI elements for what the current status is for the network

            RefreshNetworkStatus();

        }

 

        /// <summary>

        /// Load the current users’ settings.

        /// </summary>

        public void Load()

        {

            Servers = ServerPingDetailSettings.Servers;

            UseOnlyLanAndWiFi = ServerPingDetailSettings.UseOnlyLanAndWiFi;

        }

 

        /// <summary>

        /// Save the current users’ settings.

        /// </summary>

        public void Save()

        {

            ServerPingDetailSettings.Servers = Servers;

            ServerPingDetailSettings.UseOnlyLanAndWiFi = UseOnlyLanAndWiFi;

        }

 

        /// <summary>

        /// Gets a collection of <see cref=”ServerPingDetail”/> items representing servers to monitor.

        /// </summary>

        public ServerPingDetailCollection Servers { get; protected set; }

 

        /// <summary>

        /// Gets the user setting of whether only the local network should be used for pinging, as opposed to also using the cellular network.

        /// </summary>

        public bool UseOnlyLanAndWiFi

        {

            get

            { return useOnlyLanAndWiFi; }

            protected set

            {

                useOnlyLanAndWiFi = value;

                Save();

                RaisePropertyChanged(“UseOnlyLanAndWiFi”);

            }

        } bool useOnlyLanAndWiFi = true;

 

        /// <summary>

        /// Gets or sets the current status of the network for this device.

        /// </summary>

        public string NetworkStatusText

        {

            get { return networkStatusText; }

            protected set

            {

                networkStatusText = value;

                RaisePropertyChanged(“NetworkStatusText”);

            }

        } string networkStatusText = “Loading…”;

 

        /// <summary>

        /// Event handler of when the network address (status) has changed.

        /// </summary>

        /// <param name=”sender”></param>

        /// <param name=”e”></param>

        protected override void OnNetworkAddressChanged(object sender, EventArgs e)

        {

            base.OnNetworkAddressChanged(sender, e);

            RefreshNetworkStatus();

        }

 

        /// <summary>

        /// Determines the current network status, and then updates the status.

        /// </summary>

        protected void RefreshNetworkStatus()

        {

            string output = string.Empty;

            bool isAvailable = NetworkInterface.GetIsNetworkAvailable();

 

            NetworkInterfaceType currentNetworkType = NetworkInterface.NetworkInterfaceType;

 

            switch (currentNetworkType)

            {

                case NetworkInterfaceType.AsymmetricDsl:

                    output = “ADSL”;

                    break;

                case NetworkInterfaceType.Atm:

                    output = “ATM”;

                    break;

                case NetworkInterfaceType.BasicIsdn:

                    output = “Basic ISDN”;

                    break;

                case NetworkInterfaceType.Ethernet:

                    output = “Ethernet”;

                    break;

                case NetworkInterfaceType.Ethernet3Megabit:

                    output = “Ethernet (3mbps)”;

                    break;

                case NetworkInterfaceType.FastEthernetFx:

                    output = “Fast Ethernet (Fx)”;

                    break;

                case NetworkInterfaceType.FastEthernetT:

                    output = “Fast Ethernet (T)”;

                    break;

                case NetworkInterfaceType.Fddi:

                    output = “FDDI”;

                    break;

                case NetworkInterfaceType.GenericModem:

                    output = “Modem”;

                    break;

                case NetworkInterfaceType.GigabitEthernet:

                    output = “Gigabit Ethernet”;

                    break;

                case NetworkInterfaceType.HighPerformanceSerialBus:

                    output = “High Performance Serial”;

                    break;

                case NetworkInterfaceType.IPOverAtm:

                    output = “IP over ATM”;

                    break;

                case NetworkInterfaceType.Isdn:

                    output = “ISDN”;

                    break;

                case NetworkInterfaceType.Loopback:

                    output = “Loopback”;

                    break;

                case NetworkInterfaceType.MobileBroadbandCdma:

                    output = “Mobile-CDMA”;

                    break;

                case NetworkInterfaceType.MobileBroadbandGsm:

                    output = “Mobile-GSM”;

                    break;

                case NetworkInterfaceType.MultiRateSymmetricDsl:

                    output = “MRSDSL”;

                    break;

                case NetworkInterfaceType.None:

                    output = “-None-“;

                    break;

                case NetworkInterfaceType.Ppp:

                    output = “PPP”;

                    break;

                case NetworkInterfaceType.PrimaryIsdn:

                    output = “Primary ISDN”;

                    break;

                case NetworkInterfaceType.RateAdaptDsl:

                    output = “RRDSL”;

                    break;

                case NetworkInterfaceType.Slip:

                    output = “SLIP”;

                    break;

                case NetworkInterfaceType.SymmetricDsl:

                    output = “SDSL”;

                    break;

                case NetworkInterfaceType.TokenRing:

                    output = “Token Ring”;

                    break;

                case NetworkInterfaceType.Tunnel:

                    output = “Tunnel”;

                    break;

                case NetworkInterfaceType.Unknown:

                    output = “-Unknown-“;

                    break;

                case NetworkInterfaceType.VeryHighSpeedDsl:

                    output = “VHSDSL”;

                    break;

                case NetworkInterfaceType.Wireless80211:

                    output = “Wi-Fi”;

                    break;

                default:

                    output = “-Error-“;

                    break;

            }

 

            output = string.Format(“Network {0} ({1})”, (isAvailable ? “Available” : “Not Available”), output);

 

            NetworkStatusText = output;

        }

 

    }

 

Let’s assume that works for now – how do we consume that from a Silverlight or WPF page? We declare the namespace and then assign the “DataContext” for the user control like this:

<UserControl x:Class=”SederSoftware.MobilePing.Views.SettingsPageView”

    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation&#8221;

    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml&#8221;

    xmlns:d=”http://schemas.microsoft.com/expression/blend/2008&#8243;

    xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006&#8243;

    xmlns:controls=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls”

    xmlns:vm=”clr-namespace:SederSoftware.MobilePing.ViewModels”

    mc:Ignorable=”d”

    FontFamily=”{StaticResource PhoneFontFamilyNormal}”

    FontSize=”{StaticResource PhoneFontSizeNormal}”

    Foreground=”{StaticResource PhoneForegroundBrush}”

    d:DesignHeight=”480″ d:DesignWidth=”480″>

    <UserControl.DataContext>

        <vm:SummaryViewModel />

    </UserControl.DataContext>

 

What this does is set the “data context” for the page, so that when you try to bind a UI element, you will be able to bind to things that are offered from this ViewModel. For example, imagine you want to bind a TextBlock to that .NetworkStatusText property, you can do this:

image

which results in XAML like this:

<TextBlock Grid.Row=”0″ Text=”{Binding Path=NetworkStatusText}” />

 

Put another way, this textblock is now “bound” to the NetworkStatusText property of SummaryViewModel. Because we implemented INotifyPropertyChanged, whenever that property changes, this UI element will update automatically. That – is the beauty of MVVM.

WP7 Phone Specific Tasks:
OK, most of this has been about MVVM, but I did want to write down these phone-specific things:

  • Network status change  – to find out when the network status has changed (going from WiFi to Cell, or going from Cell data service to no service), subscribe to System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged
  • Get current network status – use Microsoft.Phone.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable() and the Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType enum to determine if the network is up, and what kind of connection you have.
  • Startup, shutdown, tombstoning – to do something when the app starts, or when it’s being unloaded, wire up to the events: PhoneApplicationService.Current.Activated, PhoneApplicationService.Current.Closing, PhoneApplicationService.Current.Deactivated, and PhoneApplicationService.Current.Launching
  • Navigate to other pages – use something like this: this.NavigationService.Navigate(new Uri(“/SettingsPage.xaml”, UriKind.Relative)); or even this.NavigationService.GoBack() to simulate the back button.
  • Scrollable content – if you want the content on your page to be scrollable, just throw it inside of a <ScrollViewer> control.
  • Support portrait and landscape – I have no idea why the templates default to portrait only, but in the 2000’s, smart phone apps need to support both portrait and landscape. For this, at the <phone:ApplicationPage> level, set SupportedOrientations=”PortraitOrLandscape”
  • Read/Write to “settings”, at the app/user level – use IsolatedStorageSettings.ApplicationSettings

Lastly, if you want to have icons down in the application bar like this:

image

the only way I have found to do this, is to open the project in Expression Blend and it has this option there:

image

Well, so much for my short post on this WP7 app. Since it is a nearly complete, and somewhat proper app, I plan to clean it up and I’ll probably post it in case you want to peek at the code for examples of how to do specific things.

Tagged with: , , ,
Posted in .NET 4.0, Best-practices, Mobile, Professional Development, Uncategorized, WPF and MVVM
One comment on “My notes on approaching a proper MVVM WP7 phone app
  1. […] MVVM on WP7 August 11, 2012 05:14 by Administrator http://robseder.wordpress.com/2011/06/17/my-notes-on-approaching-a-proper-mvvm-wp7-phone-app/ Tags: Categories: Actions: E-mail | Kick it! | Permalink | Kommentare (0) | Comment RSS […]

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Archives
Categories

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 5 other followers

%d bloggers like this: