Powered by

US - English
NEW! Silverlight 5 is available Learn More

Building a Windows Phone 7 Application

By Microsoft Silverlight Team|December 1, 2010

Contents

Overview

Estimated Time: 45 Minutes

Silverlight has enjoyed continued success branching out from simply a browser plug-in, to the desktop, and now it’s the platform of choice for Windows Phone 7 development. This lab is designed to guide developers through the process of developing a Silverlight application for the Windows Phone.

In the lab you'll create a package tracking application. Along the way you'll learn how to navigate between pages, work with the Maps control, and connect to a WCF service from a Windows Phone project.

You'll start by creating three screens the main screen, a details screen, and a map screen. Next, you’ll connect to a WCF service. Finally, you’ll learn how to set a custom icon for your application. The Windows Phone application that you'll create is shown next:

You Will Benefit from this Lab if:

  • You’re interested in Windows Phone 7 (WP7) development
  • You would like to see how to use existing Silverlight knowledge and tools to create and deploy a WP7 app.

You Will Learn:

  • How to start a Windows Phone 7 project.
  • How to use existing tooling, Visual Studio and Expression Blend, with WP7
  • WP7 specific controls
  • How to access data
  • Similarities between Silverlight for WP7 and Silverlight for desktop

Business Requirements for the Silverlight application include:

  • Create a Windows Phone project for tracking packages
  • Add three screens: Search, Details, and details map
  • Call a WCF service
  • Create a custom icon

Exercise 1: Create User Interface

Watch Video

If you already know how to create a new project, open the starting solution and add a new project instead, and move to step 2

  1. Like other projects, create a new project by opening Visual Studio and selecting File > New Project. In the New Project dialog box, as seen in the image below, select Silverlight for Windows Phone in the Installed Templates panel. Notice there are a number of preinstalled Windows Phone templates:
    • A basic Application
    • A Databoud Application
    • Class Library
    • A Panorama Application
    • A Pivot Application
    For simplicity, this Lab uses the basic Windows Phone Application

    If you don’t see Silverlight for Windows Phone in the Installed Templates list, Make sure: The tools installed correctly, you can download them from: http://www.silverlight.net/getstarted/devices/windows-phone/ You have selected Visual C# instead of Visual Basic. Currently VB is not supported on the Windows Phone 7 platform.

  2. Call the Solution PackageTracker and the Project UPSTracking.WP7 and click OK
  3. Add the projects from the starter solution to your solution: The projects in the starter solution provide the package tracking service functionality that we will use to store and get a list of items to track, and also the classes needed to support them.
  4. Copy the dotNetShipping and UPSTrackingService folders to your solution folder. They are located either in Package Tracker > Source > Starting Point > C# or in Package Tracker > Source > Starting Point > VB, you can use whichever one you prefer.Right click on your solution, and choose Add > Existing Project
  5. In the Add Existing Project Dialog, find and select the dotNetShipping project, and click Open . Right click on your solution again, and this time add the UPSTrackingService project Your solution should look like this: Add controls for searching
    • After creating a new project, a number of files are created, one of them being MainPage.xaml. This is the first page seen. Here we’ll add a number of elements:
    • A TextBox to enter a tracking number
    • A Button to trigger the search
    • A TextBlock for the header
    • A ListBox to show recently searched packages
    Add these controls the same way you would in any Silverlight project, by dragging and dropping them from the Toolbox or creating the Xaml by hand. The Screenshot below shows the resulting UI and the code snippet shows the Xaml for this UI:

    XAML

    <Grid x:Name="LayoutRoot" Background="White">
           <Grid Margin="12,70,12,12" d:LayoutOverrides="Width">
                 <Grid.ColumnDefinitions>
                      <ColumnDefinition/>
                      <ColumnDefinition Width="331"/>
                 </Grid.ColumnDefinitions>
                 <ListBox x:Name="ResultsListBox">
                      <ListBox.ItemTemplate>
                            <DataTemplate>
                                 <Grid Margin="3,3,3,8" d:DesignWidth="349.5" d:DesignHeight="59">
                                     <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="80"/>
                                            <ColumnDefinition Width="75"/>
                                            <ColumnDefinition Width="75"/>
                                            <ColumnDefinition Width="Auto"/>
                                     </Grid.ColumnDefinitions>
                                     <TextBlock Text="{Binding ActivityDate, FallbackValue=6/10/1999}" d:LayoutOverrides="GridBox" Grid.Column="1" Margin="3" TextWrapping="Wrap"/>
                                     <TextBlock Text="{Binding ActivityTime, FallbackValue=12:00 PM}" Margin="3" d:LayoutOverrides="GridBox" Grid.Column="2" TextWrapping="Wrap" />
                                     <TextBlock Text="{Binding StatusDescription, FallbackValue=DELIVERED}" Margin="3" d:LayoutOverrides="GridBox" Grid.Column="3" TextWrapping="Wrap"/>
                                     <toolkit:WrapPanel Margin="3">
                                            <TextBlock Text="{Binding City, FallbackValue=ANYWHERE}" Margin="0" TextWrapping="Wrap" />
                                            <TextBlock Text=", " Margin="0" TextWrapping="Wrap" />
                                            <TextBlock Text="{Binding CountryCode, FallbackValue=US}" Margin="0" TextWrapping="Wrap" />
                                            <TextBlock Text=", "Margin="0" TextWrapping="Wrap" />
                                            <TextBlock Text="{Binding State, FallbackValue=GA}" Margin="0" TextWrapping="Wrap"/>
                                     </toolkit:WrapPanel>
                                 </Grid>
    

    You can delete everything inside LayoutRoot to simplify the Xaml for this sample

  6. Now the UI is created for the user to enter a tracking number, we need a search results page. Here we’ll show the current status and the history of where the package has been.
  7. To create a new page, right click the project select Add>New Item from the context menu. You will then be prompted as to which type of page to create. Select the Windows Phone Portrait Page and name it PackageDetails.xaml.
  8. Once created, add controls to look similar to the image below. The details Grid contains TextBlocks for labels and for showing the results, and the ListBox, will contain the historical information about where the package has been.

    Once again, to simplify the Xaml, you can delete everything in the LayoutRoot by default

    XAML

    <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                    <RowDefinition Height="0.293*"/>
                    <RowDefinition Height="0.707*"/>
            </Grid.RowDefinitions>
            <Border BorderBrush="Black" BorderThickness="1" Margin="0">
                    <Border.Background>
                            <RadialGradientBrush GradientOrigin="0.492,-0.338" RadiusX="0.915" RadiusY="0.827" Center="0.49,0.338">
                                    <GradientStop Color="#FF4E4E4E" Offset="0"/>
                                    <GradientStop Color="#FF1D1D1D" Offset="1"/>
                            </RadialGradientBrush>
                    </Border.Background>
            </Border>
            <Grid x:Name="LatestStatusGrid" Margin="12,8,12,59">
                    <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
                            <RowDefinition />
             </Grid.RowDefinitions>
             <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="0.296*"/>
                            <ColumnDefinition Width="0.704*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Status" d:LayoutOverrides="Height" VerticalAlignment="Top" Margin="2"/>
                    <TextBlock TextWrapping="Wrap" Text="Last updated" d:LayoutOverrides="Width, Height" Grid.ColumnSpan="2" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2"/>
                    <TextBlock TextWrapping="Wrap" Text="Location" d:LayoutOverrides="Width" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="2"/>
                    <TextBlock TextWrapping="Wrap" Text="Tracking #" d:LayoutOverrides="Width, Height" Grid.Row="3" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="2"/>
                    <TextBlock TextWrapping="Wrap" Text="{Binding StatusDescription}" Grid.Column="1" d:LayoutOverrides="Height" Margin="2" FontWeight="Bold"/>
                    <TextBlock TextWrapping="Wrap" Text="{Binding ActivityDate}" Grid.Column="1" Grid.Row="1" d:LayoutOverrides="Height" Margin="2" FontWeight="Bold"/>
                    <StackPanel d:LayoutOverrides="Width" Grid.Row="2" Grid.Column="1" Margin="0" Orientation="Horizontal">
                            <TextBlock Text="{Binding City}" TextWrapping="Wrap" VerticalAlignment="Top" Margin="5,0,4,0" FontWeight="Bold" />
                            <TextBlock Text="{Binding State}" Margin="0,0,4,0" TextWrapping="Wrap" HorizontalAlignment="Left" />
                            <TextBlock Text="{Binding CountryCode}" Margin="5,0,0,0" TextWrapping="Wrap" HorizontalAlignment="Left" d:LayoutOverrides="HorizontalMargin" />
                    </StackPanel>
                    <TextBlock TextWrapping="Wrap" Text="{Binding TrackingNumber}" Grid.Column="1" Grid.Row="3" d:LayoutOverrides="Height" Margin="2" FontWeight="Bold"/>
            </Grid>
            <Button x:Name="MapButton" Content="MAP THIS" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,0,-5"/>
            <ListBox x:Name="PackageHistoryList" Grid.Row="1"></ListBox>
    </Grid>
    

    Notice that we used Binding to bind all the TextBlocks to the Properties of a TrackingActivity class from the dotNetShipping project since later on, this page will always be bound to a certain TrackingActivity object

  9. The next step will answer the question “How do we get from the MainPage to the PackageDetails?”
  10. Wire up the Track Button Back on the MainPage.xaml, add a Click event Handler for the TrackButton. Here you’ll get the first taste of how to navigate between pages in a WP7 application. Going to the PackageDetails page will feel very similar to an ASP.NET application. First construct the URL using the NavigationService, then navigate to that page.

    When creating the url a query string value that contains the tracking number is passed in. The results page will consume this value and then query for results.

    C#

    private void TrackButton_Click(object sender, RoutedEventArgs e)
    {
            // Pass the tracking number to the next page
            Uri theUri = new Uri("/PackageDetails.xaml?trackingNumber=" + TrackingNumber.Text, UriKind.Relative);
            NavigationService.Navigate(theUri);
    }
    
  11. In the PackageDetails.xaml.cs page add a Loaded event handler. In the Loaded event, check to see if a tracking number was passed through the query string. This ties the Navigation Loop. In the next section, we’ll add to this event handler by calling the service to get the tracking status.

    C#

    private void PackageDetails_Loaded(object sender, RoutedEventArgs e)
    {
            if (NavigationContext.QueryString.ContainsKey("trackingNumber"))
            {
                    var trackingNumber = NavigationContext.QueryString["trackingNumber"];
            }
    }
    

Exercise 2: Calling Service

Add a service reference

  1. From the WP7 project, right click and select Add Service Reference. In the Service Reference dialog box select Discover, as seen in the screenshot
  2. Name the service PackageTrackingService, click OK and your service is now added.

    Notice if the service doesn’t add properly and isn’t recognized as a namespace in your project, you can try to remove the service reference, clean the solution ,close Visual Studio and try to add the Service Reference again

  3. To call the service add the code below to the PackageDetails.xaml.cs Loaded handler in the end of the if statement

    C#

    var client = new Service1Client();
    client.GetTrackingActivityAsync(trackingNumber);
    client.GetTrackingActivityCompleted +=   client_GetTrackingActivityCompleted;
    

    Service1Client is located in the PackageTracker.PackageTrackingService namespace There are a couple of things to Notice the if statement contains a check to see if there is a parameter in the navigation query string: NavigationContext.QueryString.ContainsKey("trackingNumber") If the tracking number exists, then a new ServiceClient is created, the value is sent, and finally the event handler for the completed event is registered.

  4. We will need to save the CurrentPackage in the application to simplify transferring this information to the map page, so we’ll add a property for the current package in App.xaml.cs.

    C#

    public static Shipment CurrentPackage { get; set; }
    
  5. In the completed event handler, get the results, sort them, set the ListBox’s ItemSource, and finally set the DataContext of the LatestStatusGrid

    C#

    void client_GetTrackingActivityCompleted(object sender, GetTrackingActivityCompletedEventArgs e)
    {
            if (e.Error == null)
            {
                    App.CurrentPackage = e.Result;
                    var sortedList = e.Result.TrackingActivities.OrderBy((a) =>
                    a.ActivityDate).Reverse();
                    if (sortedList.Count() == 0) return;
                    this.PackageHistoryList.ItemsSource = e.Result.TrackingActivities;
                    LatestStatusGrid.DataContext = sortedList.Last();
            }
    }
    
  6. Your page now gets data and displays it back to the user.

Exercise 3: Showing the Map

  1. Add a reference to Microsoft.Phone.Controls.Maps
  2. Create a new Windows Phone Portrait Page in your project and call it DetailsMap.xaml
  3. Map the Microsoft.Phone.Controls.Maps assembly to an xml namespace in DetailsMap.xaml

    XAML

    xmlns:Microsoft_Phone_Controls_Maps="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
    
  4. Add a new BingMap control to the DetailsMap.xaml Page

    XAML

    <Grid x:Name="LayoutRoot" Background="Transparent">
            <Microsoft_Phone_Controls_Maps:Map  x:Name="Map" ZoomLevel="4" LogoVisibility="Collapsed" ZoomBarVisibility="Visible"/>
    </Grid>
    
  5. In the PackageDetails page there was a button labeled MAP THIS. Add the following click event handler to the Click event of the MapButton.

    C#

    private void MapButton_Click(object sender, RoutedEventArgs e)
    {
            Uri theUri = new Uri("/DetailsMap.xaml", UriKind.Relative);
            NavigationService.Navigate(theUri);
    }
    
  6. This is very similar to the MainPage’s TrackButton event handler, but instead we’re navigating to the DetailsMap.xaml.
  7. Since the map is going to display locations where the package has been, we’ll need one more web service reference that geocodes the locations returned from the package tracking service. There are many out there, but in this example we’ll be using Bing Maps Geocoding service, http://www.codeproject.com/KB/IP/BingMapsWebServiceExample.aspx.

  8. To add this service reference, add a Service Reference as you normally would, but instead of clicking Discover, add the next address: http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc?wsdl into the Address field, and click Go.
  9. Call the Service GeocodeService and click OK
  10. Once the Service is added and you have your own key, call the service from DetailsMap Loaded event like the following code.

    C#

    private void DetailsMap_Loaded(object sender, RoutedEventArgs e)
    {
            string key = "YOUR KEY";
            // Configure the request object
            GeocodeRequest request = new GeocodeRequest();
            request.Credentials = new UPSTracking.WP7.GeocodeService.Credentials();
            request.Credentials.ApplicationId = key;
    
            // Initialize the client
            GeocodeService.GeocodeServiceClient client = newGeocodeServiceClient("BasicHttpBinding_IGeocodeService");
            client.GeocodeCompleted += new EventHandler<GeocodeCompletedEventArgs>(client_GeocodeCompleted);
    
            // loop through each activity and make a request
            foreach (var activity in App.CurrentPackage.TrackingActivities)
            {
                    request.Query = string.Format("{0} {1} {2}", activity.City, activity.State, activity.CountryCode);
                    client.GeocodeAsync(request);
            }
    }
    

    For this sample, your Bing Maps Key is: AsrtnIJN_DSjg1772uR7pUmW6gRNL5gdXwcaZkNo_qIYG0h2YXdg7ShFPpUht342

  11. In the Completed event, add the following code block to add a Pin for each result.

    C#

    void client_GeocodeCompleted(object sender, GeocodeCompletedEventArgs e)
    {
            if (e.Error == null)
            {
            // The result is a GeocodeResponse object
            GeocodeResponse geocodeResponse = e.Result;
    
            // Get the latitude and longitude for the first item in the results
            var latitude = geocodeResponse.Results[0].Locations[0].Latitude;
            var longitude = geocodeResponse.Results[0].Locations[0].Longitude;
            var altitude = geocodeResponse.Results[0].Locations[0].Altitude;
            // Create a new pushpin
            Pushpin pin = new Pushpin()
            {
                    Content = e.Result.Results[0].Address.FormattedAddress.ToString(),
                    Location = new System.Device.Location.GeoCoordinate(latitude,longitude,altitude) };
            // Add the pushpin to the Map
            this.Map.Children.Add(pin);
            this.Map.Center = pin.Location;
            this.Map.ZoomLevel = 5d;
            }
    }
    
  12. For this code to compile you will have to add the following using statements to DetailsMap.xaml.cs

    C#

    using UPSTracking.WP7.GeocodeService;
    using Microsoft.Phone.Controls.Maps;
    
  13. You will also need to add a reference to System.Device

Exercise 4: Customizing the application

The icon for your application will enable users to quickly identify your application. So it’s important to make sure you find or create a unique icon. In our case we will use the below icon.

  1. Add an icon to the project by right clicking the project > Add Item > Existing Item then selecting the icon.
  2. In order for the icon to appear, make sure to set the Build action as Content, otherwise your project won’t be able to run on either the emulator or device. To set the build action, click the newly imported image, open the properties window, and select Content from the Build Action drop down.
  3. Open up the Properties by right clicking the project and selecting Properties. Here you will see this menu.
  4. Under Deployment change the Title and Icon to Package Tracker and package_icon.png respectively.

Exercise 5: Finalization and Esthetics

In MainPage.xaml we have a list that represents our shipped items, but it is not bound to any data and doesn’t provide any functionality, so we want to make it display a list of shipments that we sent, as it loads.

  1. To bind the list to shipments we made, we need to have a property in MainPage.xaml.cs that we can bind it to. For simplicity reasons we use List instead of and ObservableCollection assuming it will not change in real time. To do so, we also need to add a using statement to our PackageTrackingService

    C#

    using UPSTracking.WP7.PackageTrackingService;
    ...
    private List<Shipment> MyShipments { get; set; }
    
  2. We also want to populate this list as soon as the main page is constructed to make it available to the page, so we will add a method call in the constructor to a method that will do any logic that will populate the list, for this sample it will be hardcoded data of shipment by tracking number. This method will also be responsible to bind the display list to the collection we just populated.

    C#

    // Pre-Populate the shipments in the C'tor
    this.PopluateMyShipments();
    private void PopluateMyShipments()
    {
            //Insert your logic instead of the code below
            MyShipments = new List<Shipment>()
            {
                    new Shipment(){TrackingNumber = "1Z12345E0291980793"},
                    new Shipment(){TrackingNumber = "1Z12345E6692804405"},
                    new Shipment(){TrackingNumber = "1Z12345E0390515214"},
                    new Shipment(){TrackingNumber = "1Z12345E1392654435"},
                    new Shipment(){TrackingNumber = "1Z12345E6892410845"},
            };
            //Insert your logic instead of the code above
    
            //Bind the collection of packages we just filled to the UI
            this.MyPackagesList.ItemsSource = MyShipments;
    }
    
  3. Now we want to enable tracking of our packages without entering the number manually, so we will add a handler to the SelectionChanged event of MyPackagesList in the constructor.

    C#

    this.MyPackagesList.SelectionChanged += new SelectionChangedEventHandler(MyPackagesList_SelectionChanged);
    
  4. And we will use the same navigation to PackageDetails page as we did in the Track button

    C#

    void MyPackagesList_SelectionChanged(object sender,SelectionChangedEventArgs e)
    {
            if (MyPackagesList.SelectedItem != null)
            {
                    var selectedShipment = (MyPackagesList.SelectedItem as Shipment);
                    if (selectedShipment != null)
                    {
                            Uri theUri = new Uri("/PackageDetails.xaml?trackingNumber=" +selectedShipment.TrackingNumber, UriKind.Relative);
                            NavigationService.Navigate(theUri);
                    }
            }
    }
    
  5. Now out application has a way to pre-populate the list with a collection of our packages so that we don’t have to enter the tracking numbers manually. Run the application and see it working.

Exercise 6: Finalizing the UI by using data templates and styles

As you might have noticed, the Shipments in our MainPage, and the TrackingActivities in out PackageDetails page show as a string representation of the class using a ToString, which makes no sense and looks less then appealing, we want to fix that.

  1. Using a data template to change the way classes appear in our UI
  2. We will start off in MainPage.xaml and make a data template which will represent a Shipping class

    XAML

    <DataTemplate>
            <StackPanel>
                    <TextBlock Margin="0" TextWrapping="Wrap" Text="{Binding TrackingNumber}" Style="{StaticResource PhoneTextLargeStyle}" Foreground="{StaticResource PhoneContrastForegroundBrush}"/>
                    <TextBlock TextWrapping="Wrap" Text="Status " VerticalAlignment="Top" Foreground="{StaticResource PhoneContrastForegroundBrush}" Visibility="Collapsed"/>
                    <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Top" Visibility="Collapsed">
                            <TextBlock TextWrapping="Wrap" Text="Tracking # " d:LayoutOverrides="Height" Style="{StaticResource PhoneTextSmallStyle}" 
                            Margin="0,0,3,0" FontSize="13.333" Foreground="{StaticResource PhoneContrastForegroundBrush}" Opacity="0.565"/>
                            <TextBlock TextWrapping="Wrap" Text="{Binding TrackingNumber}" d:LayoutOverrides="Height" Style="{StaticResource PhoneTextSmallStyle}" Margin="0,0,3,0" FontSize="13.333" 
                            Foreground="{StaticResource PhoneContrastForegroundBrush}" Opacity="0.565"/>
                    </StackPanel> 
            </StackPanel>
    </DataTemplate>
    

    We bound each field directly to the corresponding property name of the Shipment class, since we know the ListBox that we will apply it to, will always contain Shipment items.

  3. Next, we will use this data template in the ListBox.ItemTemplate property of the ListBox, this way we will both bind the template to each item in the ListBox individually, and assure that the template’s data context is always a Shipment.

    XAML

    <ListBox x:Name="MyPackagesList" Margin="0,199,0,0"d:LayoutOverrides="VerticalAlignment" Width="480">
            <ListBox.ItemTemplate>
                    <DataTemplate>
                            <StackPanel>
                                    <TextBlock Margin="0" TextWrapping="Wrap" Text="{Binding TrackingNumber}" Style="{StaticResource PhoneTextLargeStyle}" Foreground="{StaticResource PhoneContrastForegroundBrush}"/>
                                    <TextBlock TextWrapping="Wrap" Text="Status " VerticalAlignment="Top" Foreground="{StaticResource PhoneContrastForegroundBrush}" Visibility="Collapsed"/>
                                    <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Top" Visibility="Collapsed">
                                    <TextBlock TextWrapping="Wrap" Text="Tracking # " d:LayoutOverrides="Height" Style="{StaticResource 
                                    PhoneTextSmallStyle}" Margin="0,0,3,0" FontSize="13.333" Foreground="{StaticResource PhoneContrastForegroundBrush}" Opacity="0.565"/>
                                    <TextBlock TextWrapping="Wrap" Text="{Binding TrackingNumber}" d:LayoutOverrides="Height" Style="{StaticResource PhoneTextSmallStyle}" Margin="0,0,3,0" FontSize="13.333" Foreground="{StaticResource PhoneContrastForegroundBrush}" Opacity="0.565"/>
                                    </StackPanel> 
                            </StackPanel>
                    </DataTemplate>
            </ListBox.ItemTemplate>
    </ListBox>
    
  4. Now we will do the same the PackageHistoryList in PackageDetails.xaml,

    XAML

    <ListBox x:Name="PackageHistoryList" Grid.Row="1" >
            <ListBox.ItemTemplate>
                    <DataTemplate>
                            <StackPanel Margin="3,3,3,8" d:DesignWidth="349.5" d:DesignHeight="59">
                            <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,0,0,8">
                            <TextBlock Text="{Binding City}" TextWrapping="Wrap" HorizontalAlignment="Left" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            <TextBlock Text=", " TextWrapping="Wrap" d:LayoutOverrides="Width" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            <TextBlock Text="{Binding CountryCode}" TextWrapping="Wrap" HorizontalAlignment="Left" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            <TextBlock Text=", " TextWrapping="Wrap" d:LayoutOverrides="Width" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            <TextBlock Text="{Binding State}" TextWrapping="Wrap" HorizontalAlignment="Left" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            </StackPanel>
                              <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,0,0,8">
                            <TextBlock Text="{Binding ActivityTime}" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            <TextBlock Text="{Binding ActivityDate}" TextWrapping="Wrap" VerticalAlignment="Top" Foreground="{StaticResource PhoneContrastForegroundBrush}" />
                            </StackPanel>
                            <TextBlock Text="{Binding StatusDescription}" TextWrapping="Wrap" HorizontalAlignment="Left" Foreground="{StaticResource PhoneContrastForegroundBrush}" Margin="0"/>
                            </StackPanel>
                    </DataTemplate>
            </ListBox.ItemTemplate> 
    </ListBox>
    
  5. Templating is done, and our application now displays relevant data about each item, but its style and font are bound to the phone’s defaults which might sometimes be hard to see on our UI’s background.
  6. As you’ve already seen, now all of our UI shows appropriate information but it might be a bit hard to see, so we would like to change that, we could go to each TextBlock and modify it manually, but we can go even further and use a style, to give our UI a unified look across all our pages that we can store once and change on request.

  7. To make our styles available for the whole application, we will put them in the resources section of App.xaml

    XAML

    <Application.Resources>
    <Style x:Key="DetailsListBoxItemStyle" TargetType="ListBoxItem">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="HorizontalContentAlignment" Value="Left"/>
            <Setter Property="VerticalContentAlignment" Value="Top"/>
            <Setter Property="Template">
            <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                            <Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Width="480">
                                    <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="MouseOver"/>
                                    <VisualState x:Name="Disabled">
                                    <Storyboard>
                                            <DoubleAnimation Duration="0" To=".5" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ContentContainer"/>
                                    </Storyboard>
                                    </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected"/>
                            <VisualState x:Name="Selected">
                            <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneAccentBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                            </VisualState>
                            </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                                <Border BorderThickness="0,0,0,1" Margin="0" BorderBrush="#FF333333">
                    <Border.Background>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFF3F3F3" Offset="0"/>
                    <GradientStop Color="#FFDADADA" Offset="0.996"/>
                    </LinearGradientBrush>
                    </Border.Background>
                    </Border>
                    <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" 
                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" Margin="15"/>
                            </Grid>
                    </ControlTemplate>
            </Setter.Value>
            /Setter>
            </Style>
    </Application.Resources>
    

    This is a unified style that we created for all items that display details about items, we will use it both in MainPage.xaml and in PackageDetails.xaml

  8. To bind the style to the ListBoxItems use

    XAML

    ItemContainerStyle="{StaticResource DetailsListBoxItemStyle}"
    
  9. Now our application is done, run it and see the new Styles

    You can style the application further, the solution contains added styles for the 2 ListBoxes in MainPage.xaml and PackageDetails.xaml, but it’s purely esthetic.

References

Geocoding: http://www.codeproject.com/KB/IP/BingMapsWebServiceExample.aspx

Namespace Address
GeocodeService http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc?wsdl
SearchService http://dev.virtualearth.net/webservices/v1/searchservice/searchservice.svc?wsdl
ImageryService http://dev.virtualearth.net/webservices/v1/imageryservice/imageryservice.svc?wsdl
RouteService http://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc?wsdl

Account Name - SchumanCorey140209

Bing Maps key - AsrtnIJN_DSjg1772uR7pUmW6gRNL5gdXwcaZkNo_qIYG0h2YXdg7ShFPpUht342

Summary

In this exercise you examined an existing ASP.NET application and supporting data access and service layers. You then migrated the existing functionality in the application to Silverlight and satisfied the following requirements:

  • Create a Windows Phone project for tracking packages
  • Add three screens: Search, Details, and details map
  • Call a WCF service
  • Create a custom icon

Although the application created in this lab demonstrates how XAML and managed code can be used, other labs will provide additional details about application design practices that can be followed such as the Model-View-ViewModel (MVVM) pattern that you can use to build Silverlight applications.

Microsoft Silverlight Team

By Microsoft Silverlight Team, Silverlight is a powerful development platform for creating engaging, interactive user experiences for Web, desktop, and mobile applications when online or offline.

Comments (0)