i2W: An iPhone Developer’s First Windows Phone 7 Application

i2WLogo2

Go to first Tutorial

In this tutorial we will build a meaningful, and nontrivial Windows phone 7 application. This will give us the opportunity to explore layout controls, interactive controls, Visual Studio and a good bit more.

[Updated 8/30/2010]

form Let’s start by taking a look at the application were going to build.

The application opens with a form, and that form is populated by data binding.

Note: All images are cropped. To see the full size (but still cropped) version, double click on the image

Let’s walk through the creation of this first demo program step by step.

A Word On The Development Environment

Before we begin, let me note that I make the assumption that you are a professional iPhone developer, and thus are not afraid to invest in purchasing the right tools.

While, as noted in the previous tutorial, it is possible to write Windows Phone 7 applications using Visual Studio Express, I will demonstrate using Visual Studio 2010 Ultimate.

In addition, as a practical matter, MVVM (the principle design pattern for Windows Phone 7) is easiest when supported by a library, and so I will use the free MVVM Light Toolkit.

Additionally, you’ll notice that my screen shots include a menu member Resharper and/or Code Rush; using one of these two supplements to Visual Studio is not required, but they do provide a far more efficient programming experience.

Visual Studio, Expression Blend, XCode and Interface Builder

It is tempting to draw a parallel in which Visual Studio maps to XCode and Expression Blend maps to Interface Builder.  This isn’t wrong so much as incomplete, because you can create your entire interface in Visual Studio (and many folks do) but for more advanced UI development, Blend is the tool of choice.  We could start off by creating the form itself in Blend (and some would argue we should) but we’ll keep things simple by doing all our work for now in Visual Studio, introducing Blend in a following tutorial.

Solutions, Projects and Files, Oh My

MVVM For Phone To begin, open Visual Studio, click on New Project and in the left pane (Templates) choose Visual C# and then Silverlight For Windows Phone 7. In the right hand side, choose the MVVM Light Toolkit. Give Visual Studio 2010 a few minutes to settle down and you’ll find that Visual Studio 2010 and the MVVM Light Toolkit have cooperated to create a project with numerous files and folders.  You can see these in Solution Explorer window, which is typically on the upper left hand side of your development environment and which you can open either from the menu (View->Solution Explorer) or with the hot keys that are shown on the menu.

Because all such windows can be opened from a menu, I will eschew walking you through each, and will only point out those menu choices which may be otherwise confusing.

For now, we’ll ignore the Properties and Reference items (though feel free to explore on your own, just take a compass and plenty of rope and you’ll be fine).

The key files we care about right now are MainPage.xaml and, under the ViewModel folder MainViewModel.cs.  The former, MainPage.xaml has an associated code behind file which you can expose with the very familiar turn down.

Double click on MainViewModel.cs to populate the edit windows. Your initial view will be a split pane with the design view on one side and the code view on the other.  The code view, in this case, will be populated with a good bit of Xaml.  We’ll close the Xaml window for now to focus on the Design view.

A Very Quick Tour of Visual Studio

To close the Code View make sure the Design View it is on the left (you can switch it with the double arrow button DoubleArrow between the panes) and then click the double-arrowhead DoubleArrowHead to close the code view. Finally, make sure that the Properties window is  visible on the right (F4) and the toolbox is pinned open on the left ( Control-Alt-X).  In the illustration below, I’ve labeled 7 areas. Let’s go over them one by one:

Visual Studio

Area 1 is the toolbox. Note that at the upper right hand corner (circled) are three symbols. The first allows you to

Area 2 is the Application String and Area 3 is the Page Title string; we’ll return to these shortly.

Area 4 is the ContentPanel  and we’ll be doing most of our design work here.

Area 5 is the Solution Explorer, which is above the Properties window by convention (you can of course move any window to any position)

The properties window is divided into area 6, where the name of the selected object is set and where you can switch the properties window from Properties view to Events view (more on events later in this tutorial).  Area 7 is where the properties are set (you can see some of the Text properties exposed in this illustration).

Note the arrows emanating from the design panel.  The upper two are used to switch between Code and Design when one of the windows is hidden.  The lower three split the window vertically or horizontally, and reveal (or hide) the right hand (or lower) window respectively.

Online Help' Above all of this is the menu and of course the most important menu entry is Help, which offers a variety of ways to receive help. To see one of its most powerful features at work, place the cursor anywhere in the RowDefinition keyword (approximately line 47) and press F1.  The first time you press F1 you’ll be asked if you want to use local or internet help. If you have an internet connection, by all means ask for online help. A browser window will open with help on the RowDefinition keyword. Sweet.

As of this writing the on-line help file has tabs for each supported language. We’ll use the C# tab (which will set the C# tab for the entire page and which is sticky and thus persists to the next time you open the window).

Each entry follows the pattern of identifying the class, the namespace and assembly (we’ll cover both as we go). Syntax is demonstrated by language, and the Remarks section provides detailed information and links to related topics.

The examples section follows the Remarks section and provides copyable code to get you started.

After the Examples come the Inheritance Hierarchy, showing where your class fits in, and notes on Thread Safety, Platform, Versions and, finally a See Also section for related topics.

You also have much of this information locally in Silverlight.chm – a Windows Help file that was loaded when you installed Silverlight.

Creating The Form

Let’s return to the project and begin to create the form. For now we’re going to do all the work in the design view, though you’ll see later that everything done in Design view instantly updates the Xaml view, and vice versa.

Layout Controls

It is common to distinguish those controls used for layout from those used for interacting with the user, though the distinction is, in truth arbitrary.  In any case, there are quite a few layout controls, though the two we care most about are the Grid and the StackPanel.

The Grid is the most powerful and (nearly) ubiquitous layout control – something of a UITableView on steroids. Click in the Content Panel (area 4 above) and the edges of the Grid that was placed there for you will light up.   Move your cursor in the margin and lines will appear. Click and horizontal lines become rows, vertical lines become columns.  You’ll want to create two columns (the left taking about 1/3 of the grid) and 8 rows of approximately equal size.

Click in the Grid and notice that the properties window has a ColumnDefinitions property and a RowDefinitions Property.  Here you can make the spacing more exact.  You can do so with precise sizes (e.g., 25px) or with percentages, or with relative sizing (e.g., 2* and 3* will create two columns with the first taking 2/5 of the available space.).  I chose 1* (which you can shorten to *) and 2* for the columns, and seven rows of 1*.

You can of course open these instead of creating the rows and columns first in the designer.

Setting the Application Name and the Page Title

Click on the Application Title or the Page Title (areas 2 and 3 above)

Properties For First TextBlock We’ll use the left column for the prompts. Drag a TextBlock (used for displaying text) into the first row (row offset 0), first column and place it more or less in the center. Then switch over to the properties window and set the following properties:

  • Name=NamePrompt  (In area 6 above)
  • Common::Text=Full Name
  • Layout::Width=auto
  • Layout::Height=30
  • Layout::HorizontalAlignment=Right
  • Layout::VerticalAlignment=Center
  • Margin=5
  • Layout::Padding=0
  • Layout::MinWidth=30
  • Layout::MinHeight=30
  • Layout::MaxWidth=0
  • Layout::MaxHeight=0
  • Layout::Grid.Column=0
  • Layout::Grid.Columnspan=1
  • Layout::Grid.Row=0
  • Layout::Grid.Rowspn=1

Adding the Remaining Prompts

Drag six more prompts onto the form, setting them identically, except for the Text and the Row.  The rows will be 1,2,3,4,5 and 7 and the Text will be

  • Street Address
  • City, State, Zip
  • Phone
  • Fax
  • Email
  • Notes

You can leave all the rest alone except that under Text you’ll want to click the Bold button and you’ll want to set the prompt names (or use the default as the only reason to have meaningful names is when you need to address the objects programmatically, which we won’t do with these labels) and don’t forget to set the Grid.Row appropriately.

The row you skipped will be used for the Male & Female RadioButtons without a prompt.

The fact that so many of the properties are identical may be giving you the willies. Not to worry, we can fix this with Styles, a topic taken up in a future tutorial.  The complete Xaml is below, to facilitate cut and paste.

Adding the Input Controls

Next, you’ll want to add the input controls. Add TextBox objects to rows 0,1,3,4,5 and 7 . Set the following properties:

  • Name=Name (or StreetAddress, etc.)
  • Common::Text=Full Name (or street address, etc.)
  • Layout::Width=300
  • Layout::Height=70
  • Layout::HorizontalAlignment=Left
  • Layout::VerticalAlignment=Center
  • Margin=5
  • Layout::Padding=0
  • Layout::MinWidth=30
  • Layout::MinHeight=30
  • Layout::MaxWidth=0
  • Layout::MaxHeight=0
  • Layout::Grid.Column=0
  • Layout::Grid.Columnspan=1
  • Layout::Grid.Row=0
  • Layout::Grid.Rowspn=1

Using the Stack Panel

You skipped over the input control for row 2 (the third from the top) because you want to place three text boxes in that row (for city, state and zip, respectively).  If you just set all three to the same row and column they will appear on top of one another. What you want is to “stack” them, but in this case not one on top of the other, rather one next to the other.

Drag a StackPanel onto the form and set its properties as follows:

  • Common:Orientation = Horizontal
  • Layout::HorizontalAlignment=Stretch
  • Layout::VerticalAlignment=Stretch
  • Margin=0
  • Layout::Padding=0
  • Layout::MinWidth=0
  • Layout::MinHeight=0
  • Layout::MaxWidth=Infinity
  • Layout::MaxHeight=Infinity
  • Layout::Grid.Column=0
  • Layout::Grid.Columnspan=1
  • Layout::Grid.Row=0
  • Layout::Grid.Rowspn=1Setting the Horizontal and vertical Alignments to stretch with no margin causes the StackPanel to expand to fill the cell. Next, place three TextBox controls within the StackPanel (on top) and set their properties as follows:
    • Name=City
    • Width=150
    • Height=70
    • HorizontalAlignment=Left
    • VerticalAlignment=Bottom
    • Margin=0,0,0,5
    • Text=City
    • Name=State
    • Width=74
    • Height=70
    • Margin=0,0,0,5
    • Text= State
    • Name=Zip
    • Width=93
    • Height=70
    • Margin=0,0,0,5
    • Text= Zip

    Notice that controls within the StackPanel do not need Grid coordinates.

    Finally, you’ll want to add the two RadioButtons in row offset 6.  Again create a StackPanel, and within the StackPanel place two RadioButton controls:

    • Name=Male
    • Content=Male
    • GroupName=Sex
    • IsChecked=True
    • Name=Female
    • Content=Female
    • GroupName=Sex
    • IsChecked=False

    The GroupName creates a Radio Button Group allowing the buttons to be mutually exclusive.

    That is your UI.

    Running the Application

    Before we go any further, if you haven’t yet done so, run the application.  You can do this by clicking Build->Rebuild Your First Application (or control-shift-B) and then clicking Debug->Run (F5) or you can skip the first step and just run, as that will force a rebuild.  Your application will come up in the emulator, with populated fields!  Hoo ha!

    When you are done enjoying the first version of your app, stop debugging (press the stop debugging button on the toolbar or Debug->Stop Debugging) but do not close the emulator.  The emulator takes a while to “boot up” and you can leave it running; it will attach to your program each time you rebuild and re-run.

    Data Binding

    Unfortunately, we are rarely called upon to populate a form with known values. Somewhat more common is to populate the form from data, often data retrieved from a database, possibly via a web service.  We won’t worry about how to retrieve the data in this tutorial, but let’s take the plunge into Data Binding – the technology of telling the View how to obtain the data it needs.  Since we are doing this with MVVM, we’ll have the ViewModel obtain the data from the Model, message it as required by business rules and then use binding to allow the View to have no code in the MainPage.xaml.cs file. (This greatly assists with testing).

    To make this work we need to do two things:

    • Create data in the Model
    • Create the View Model with public properties to which each control can bind
    • Update the View…

    Ok, Three Things, we need to

    • Create data in the Model
    • Create the View Model with public properties to which each control can bind
    • Update the View setting each control’s binding
    • Set the data…

    Four things! Yes! Four things…

    • Create data in the Model
    • Create the View Model with public properties to which each control can bind
    • Update the View setting each control’s binding
    • Set the data context
    • Pretty Red Uniforms

    Create Data In The Model

    While in a “real” application you’ll get your data from a data source such as a web service (which may in turn get the data from a database) for now we’ll create an instance of a “Customer” class right in local code. Create a Customer.cs class in the Model folder that looks like this:

    using System;
    
    namespace Your_First_Application.Model
    {
        public class Customer
        {
    
            public string First { get; set; }
            public string Last { get; set;  }
            public string Address { get; set; }
            public string City { get; set; }
            public string State { get; set; }
            public string Zip { get; set; }
            public string HomePhone { get; set; }
            public string WorkPhone { get; set; }
            public string Fax { get; set; }
            public string WorkEmail { get; set; }
            public string HomeEmail { get; set; }
            public bool IsMale { get; set; }
            public string Notes { get; set; }
            public int CreditRating { get; set;  }
            public DateTime FirstContact { get; set; }
            public DateTime LastContact { get; set; }
    
        }
    }

    C# For Objective-C Programmers

    These are called “automatic” properties.  When you write

    public string First { get; set; }

    the compiler treats it exactly as if you had written

    private string _secretvariable
    public string First
    {
       get { return _secretVariable; }
       set { _secretVariable = value; }
    }

    That is, it is as if you had created a backing store for the value (in this case the string _secretVariable) and the get accessor returned that value. The set accessor sets the value of the backing store to the value passed in to the set accessor. Here’s how you use either form

    First = "Mary";        // call the setter
    //....
    string fn = First;     // call the getter

    The first line calls the setter and the string Mary is passed in as value.

    The second line represents intervening code.

    The third line uses the getter to retrieve “Mary” and assign it to the local string variable fn.

    Why Not Use Fields?

    If we’re using automatic properties, why not use public fields? Jon Galloway points out that this is a common question and that one of the better answers was given by Scott Guthrie:

    Note about that we aren’t actually adding any logic in the getters/setters of our properties – instead we just get/set the value directly to a field.  This begs the question – then why not just use fields instead of properties?  Well – there are a lot of downsides to exposing public fields. Two of the big problems are: 1) you can’t easily databind against fields, and 2) if you expose public fields from your classes you can’t later change them to properties (for example: to add validation logic to the setters) without recompiling any assemblies compiled against the old class.

    Finishing the Customer Class

    With the properties in place we need a way to generate an instance. Best would be if we didn’t have to have an instance to create one, and so we’ll add a static method that returns a pre-filled instance.  Static methods can be called on the class rather than on an instance (as you’ll see in just a moment).

    public static Customer GetCustomer()
    {
        var newCust = new Customer(
            "Martha",
            "Washington",
            "1640 Pennsylvania Avenue",
            "New York",
            "NY",
            "11214",
            "617-555-4663",
            "781-555-9675",
            "212-555-5353",
            "jesseliberty@jesseliberty.com",
            "none",
            false,
            "VIP - Treat nicely",
            700,
            new DateTime(1955,07,10),
            new DateTime(2010,06,06));
        return newCust;
    }

    This method does nothing more than to create an instance of the class, populate its fields and then return that instanceYou would never do this in production code, but it does give us an instance of the Customer class as if we had obtained it from a web service.  All that is missing is the constructor that we’re calling (that takes a value for each property),

    public Customer(
        string first,
        string last,
        string address,
        string city,
        string state,
        string zip,
        string homePhone,
        string workPhone,
        string fax,
        string workEmail,
        string homeEmail,
        bool isMale,
        string notes,
        Int16 creditRating,
            DateTime firstContact,
            DateTime lastContact )
    {
        First = first;
        Last = last;
        Address = address;
        City = city;
        State = state;
        Zip = zip;
        HomePhone = homePhone;
        WorkPhone = workPhone;
        Fax = fax;
        HomeEmail = homeEmail;
        WorkEmail = workEmail;
        IsMale = isMale;
        Notes = notes;
        CreditRating = creditRating;
        FirstContact = firstContact;
        LastContact = lastContact;
    
    }

    That’s the model.

    The ViewModel

    The job of the ViewModel is to manage this data, bind it to the view and handle user input and user actions. We’ll postpone a discussion of user input and user actions until a future tutorial, but let’s create the view model with public properties for each of the values in the Customer that we want to display in the view. Here’s the complete MainViewModel.cs file

    using GalaSoft.MvvmLight;
    using Your_First_Application.Model;
    
    namespace Your_First_Application.ViewModel
    {
        public class MainViewModel : ViewModelBase
        {
            public string ApplicationTitle
            {
                get { return "Your First Application"; }
            }
    
            public string PageName
            {
                get { return "Customer"; }
            }
    
            private readonly Customer cust = Customer.GetCustomer();
    
            public string Name { get { return cust.First + " " + cust.Last; } }
            public string Street { get { return cust.Address; } }
            public string City { get { return cust.City; } }
            public string State { get { return cust.State; } }
            public string Zip { get { return cust.Zip; } }
            public string Phone { get { return cust.WorkPhone; } }
            public string Fax { get { return cust.Fax; } }
            public string Email { get { return cust.WorkEmail; } }
            public bool IsMale { get { return cust.IsMale == true; } }
            public bool IsFemale { get { return !IsMale; } }
            public string Notes { get { return cust.Notes; } }
        }
    }

    The first two public properties are put in place by the MVVM Light Toolkit, the 11 at the bottom are the properties to which we’ll bind the 11 user controls.

    Setting the Data Context

    Notice that the values that we’re binding to are values on the customer object. How will the UI elements know what object has these properties?  That is handled by the Data Context property of the control, or its container (grid) or the container’s container (the page).  With MVVM Light Toolkit this work is done with the DAtaContext Locator object, which you’ll find was declared in the Xaml file,

    DataContext="{Binding Main, Source={StaticResource Locator}}">

    This declaration was created for you by the MVVM Light Toolkit and so you do not have to worry about it; it just works.

    Binding at the UI Level

    Binding It is time to bind the controls to the properties in the ViewModel.  Return to the View and click on one of the TextBox controls.  Delete the content and select binding. The dialog that opens will ask which public property you wish to bind to.

    The tiny gold barrel on the line with the Text property indicates that you have a known data source.  The dialog box that opens has four tabs:

    • Source
    • Path
    • Converter
    • Options

    Source is the data context (though you can have other sources, a topic for a later tutorial)

    Path is the property to which you’ll bind

    Converter allows the binding object to convert the type and/or to format the data

    Options is where you pick one of the three types of binding:

    1. One Time
    2. One Way
    3. Two Way

    OneTime binding sets the binding and shuts down the binding connection.

    OneWay binding is for read-only data

    TwoWay binding allows the user to update the data you are displaying.  We’ll look at TwoWay binding in an early upcoming tutorial.

    Creating the UI in Xaml

    While drag and drop and setting properties works very well, you may find that your friends who do Silverlight programming do not take advantage of this. Rather they write these simple UI designs directly in the Xaml.  This is very much an artifact of the days in which coding the Xaml directly was the only option, but you may be interested in how to do such a thing.  Easy, peasy.  Return to the split screen and examine the Xaml that was generated.  Change the Xaml and see how the UI changes. Change the UI and see how the Xaml changes.  Here is the complete Xaml for our page,

    <phone:PhoneApplicationPage x:Class="Your_First_Application.MainPage"
                                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"
                                FontFamily="{StaticResource PhoneFontFamilyNormal}"
                                FontSize="{StaticResource PhoneFontSizeNormal}"
                                Foreground="{StaticResource PhoneForegroundBrush}"
                                SupportedOrientations="Portrait"
                                Orientation="Portrait"
                                mc:Ignorable="d"
                                d:DesignWidth="480"
                                d:DesignHeight="768"
                                shell:SystemTray.IsVisible="True"
                                DataContext="{Binding Main, Source={StaticResource Locator}}">
    
       <!--LayoutRoot contains the root grid where all other 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="24,24,0,12">
             <TextBlock x:Name="ApplicationTitle"
                        Text="{Binding ApplicationTitle}"
                        Style="{StaticResource PhoneTextNormalStyle}" />
             <TextBlock x:Name="PageTitle"
                        Text="{Binding PageName}"
                        Margin="-3,-8,0,0"
                        Style="{StaticResource PhoneTextTitle1Style}" />
          </StackPanel>
    
          <!--ContentPanel - place additional content here-->
          <Grid x:Name="ContentGrid"
                Grid.Row="1"
                Height="617"
                VerticalAlignment="Bottom">
             <Grid.RowDefinitions>
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="1*" />
             </Grid.RowDefinitions>
             <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1*" />
                <ColumnDefinition Width="2*" />
             </Grid.ColumnDefinitions>
             <TextBlock Height="30"
                        HorizontalAlignment="Right"
                        Margin="5"
                        Name="NamePrompt"
                        Text="Full Name"
                        VerticalAlignment="Center"
                        FontWeight="Bold"
                        Grid.Row="0" />
             <TextBlock FontWeight="Bold"
                        Height="30"
                        HorizontalAlignment="Right"
                        Name="streetPrompt"
                        Text="Street Address"
                        VerticalAlignment="Center"
                        Margin="5"
                        Grid.Row="1" />
             <TextBlock FontWeight="Bold"
                        Height="30"
                        HorizontalAlignment="Right"
                        Name="cityStateZipPrompt"
                        Text="City, State, Zip"
                        VerticalAlignment="Center"
                        Margin="5"
                        Grid.Row="2" />
             <TextBlock Height="30"
                        HorizontalAlignment="Right"
                        Margin="5"
                        Name="PhonePrompt"
                        Text="Phone"
                        VerticalAlignment="Center"
                        FontWeight="Bold"
                        Grid.Row="3" />
             <TextBlock FontWeight="Bold"
                        Height="30"
                        HorizontalAlignment="Right"
                        Name="FaxPrompt"
                        Text="Fax"
                        VerticalAlignment="Center"
                        Margin="5"
                        Grid.Row="4" />
             <TextBlock FontWeight="Bold"
                        Height="30"
                        HorizontalAlignment="Right"
                        Name="EmailPrompt"
                        Text="Email"
                        VerticalAlignment="Center"
                        Margin="5"
                        Grid.Row="5" />
    
             <TextBlock FontWeight="Bold"
                        Height="30"
                        HorizontalAlignment="Right"
                        Name="NotesPrompt"
                        Text="Notes"
                        VerticalAlignment="Center"
                        Margin="5"
                        Grid.Row="7" />
    
             <TextBox Name="FullName"
                      Width="303"
                      Height="70"
                      HorizontalAlignment="Left"
                      VerticalAlignment="Bottom"
                      Margin="5,0,0,5"
                      Grid.Column="1"
                      Text="{Binding Name}" />
             <TextBox Name="Street"
                      Width="303"
                      Height="70"
                      HorizontalAlignment="Left"
                      VerticalAlignment="Bottom"
                      Margin="5,0,0,5"
                      Grid.Row="1"
                      Grid.Column="1"
                      Text="{Binding Street}" />
             <StackPanel Orientation="Horizontal"
                         HorizontalAlignment="Stretch"
                         VerticalAlignment="Stretch"
                         Margin="0"
                         Grid.Row="2"
                         Grid.Column="1">
                <TextBox Name="City"
                         Width="150"
                         Height="70"
                         HorizontalAlignment="Left"
                         VerticalAlignment="Bottom"
                         Margin="0,0,0,5"
                         Text="{Binding City}" />
                <TextBox Name="State"
                         Width="74"
                         Height="70"
                         Margin="0,0,0,5"
                         Text="{Binding State}" />
                <TextBox Name="Zip"
                         Width="93"
                         Height="70"
                         Margin="0,0,0,5"
                         Text="{Binding Zip}" />
             </StackPanel>
             <TextBox Height="70"
                      HorizontalAlignment="Left"
                      Margin="5,0,0,5"
                      Name="Phone"
                      VerticalAlignment="Bottom"
                      Width="303"
                      Grid.Column="1"
                      Grid.Row="3"
                      Text="{Binding Phone}" />
             <TextBox Height="70"
                      HorizontalAlignment="Left"
                      Margin="5,0,0,5"
                      Name="Fax"
                      VerticalAlignment="Bottom"
                      Width="303"
                      Grid.Column="1"
                      Grid.Row="4"
                      Text="{Binding Fax}" />
             <TextBox Height="70"
                      HorizontalAlignment="Left"
                      Margin="5,0,0,5"
                      Name="Email"
                      VerticalAlignment="Bottom"
                      Width="303"
                      Grid.Column="1"
                      Grid.Row="5"
                      Text="{Binding Email}" />
             <StackPanel Orientation="Horizontal"
                         HorizontalAlignment="Stretch"
                         VerticalAlignment="Stretch"
                         Margin="5"
                         Grid.Row="6"
                         Grid.Column="1">
                <RadioButton Name="Male"
                             Content="Male"
                             GroupName="Sex"
                             IsChecked="{Binding IsMale}"
                             FontSize="20" />
                <RadioButton Name="Female"
                             Content="Female"
                             GroupName="Sex"
                             IsChecked="{Binding IsFemale}"
                             FontSize="20" />
             </StackPanel>
             <TextBox Height="72"
                      HorizontalAlignment="Left"
                      Margin="5,0,0,5"
                      Name="Notes"
                      VerticalAlignment="Bottom"
                      Width="290"
                      Grid.Column="1"
                      Grid.Row="7"
                      Text="{Binding Notes}" />
          </Grid>
       </Grid>
    </phone:PhoneApplicationPage>

    You can obtain the complete source code for this application here.

    Avoiding Property Wrappers

    An argument can certainly be made that too many of the properties in the ViewModel are nothing but pass-through wrappers for the same properties in Customer.  You can avoid that by making a Customer object a public property of the ViewModel and then binding to that directly.  If you prefer that style, you would want to change the ViewModel to look like this:

    public class MainViewModel : ViewModelBase
    {
        public string ApplicationTitle
        {
            get { return "Your First Application"; }
        }
    
        public string PageName
        {
            get { return "Customer"; }
        }
    
        private   Customer cust = Customer.GetCustomer();
        public   Customer Cust { get { return cust; } }
    
        public string Name { get { return cust.First + " " + cust.Last; } }
        public bool IsMale { get { return cust.IsMale == true; } }
        public bool IsFemale { get { return !IsMale; } }
    }

    You’ll need to update the Xaml file to bind to WorkPhone and WorkEmail (as the ViewModel is no longer translating for you).

    Finally, you’ll need to bind explicitly to the Customer property for most of the  fields, and to the ViewModel for the couple (Name and Male/Female) that will use Properties on the VM rather than on the Customer

    public MainPage()
    {
        InitializeComponent();
        var vm = new MainViewModel();
        DataContext = vm.Cust;
        FullName.DataContext = vm;
        Male.DataContext = Female.DataContext = vm;
    }

    We create an instance of the ViewModel, and then set the DataContext of the View to the Cust property of the ViewModel.  We then set the DataContext of FullName to the ViewModel instance, and finally we set Male.DataContext and FemaleDataContext to the vm as well.

    Mind Map

    This is the kind of thing that people who like this kind of thing like.

    [Click on the map to see it full size]

    Go to next tutorial

  • About Jesse Liberty

    Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
    This entry was posted in iPhoneToWP7, Mini-Tutorial, Tools and Utilities, WindowsPhone and tagged , , , , . Bookmark the permalink.

    7 Responses to i2W: An iPhone Developer’s First Windows Phone 7 Application

    Comments are closed.