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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Archives
Categories

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

Join 9 other followers

%d bloggers like this: