31 Days of Mango | Day #25: Background Agents

Day25-BackgroundAgentsDay24-ProfilerToolDay23-ExecutionModelDay22-AppConnectDay21-Sockets

This article is Day #25 in a series called 31 Days of Mango, and was written by guest author Gary Johnson.  Gary can be reached on Twitter at @GaryGJohnson.

Today we’re going to take a look at one of the multitasking capabilities new to Windows Phone 7.5. The complete multitasking picture is comprised of several new features:

  • Background Agents
  • Background File Transfer
  • Background Audio Playback
  • Scheduled Notifications
  • Fast Application Switching

Here we will focus on Background Agents. While the file transfer and audio playback tasks cover specific scenarios, they do not allow for custom code to be executed. That is where Background Agents come in.

There are two types of Background Agents: Periodic and Resource Intensive. Resource Intensive agents are meant for tasks that will consume a large amount of system resources and come with several limitations for when they can be run. Periodic agents run more frequently and with less restriction, but are meant for tasks that are light on resource consumption. To fully understand the different limitations and benefits of each, refer to the MSDN page.

A periodic task might do something short and simple, such as refresh an RSS feed or update your live tile. A resource intensive task might do something that requires a lot of time and bandwidth, such as syncing or caching large amounts of data from a cloud service.

We are going to make a Periodic Agent that will update your application live tile with the last time the custom task was run.

Getting Started

Launch Visual Studio and create a new project. Under Silverlight for Windows Phone, select Windows Phone Application. Name it “MyAgentApp”.

clip_image002

You’ve now created the main application. It will be responsible for two things:

1) Having a live tile that the Background Agent can update with information

2) Starting and stopping the Background Agent

The Background Agent itself must live in its own special project. Add a new project to your solution, selecting Windows Phone Scheduled Task Agent. Name it MyAgent. This project will contain your custom code that will run in the background and update the live tile.

clip_image004

Finally, and this is important, go to the MyAgentApp project and add a project reference to MyAgent. This will allow you to register your agent from within the application. Also, notice the entry this automatically created in WMAppManifest.xml:

<Tasks>
      <DefaultTask Name="_default" NavigationPage="MainPage.xaml" />
      <ExtendedTask Name="BackgroundTask">
        <BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="MyAgent" Source="MyAgent" Type="MyAgent.ScheduledAgent" />
      </ExtendedTask>
    </Tasks>
 

Creating the Application

Now it’s time to actually wire everything up. Open MainPage.xaml and add two buttons, one for starting the agent, and the other for stopping the agent:

<StackPanel VerticalAlignment="Center">
        <Button Content="Start Background Agent"
               Click="StartButton_Click"/>
        <Button Content="Stop Background Agent"
               Click="StopButton_Click"/> 
    </StackPanel>
 

 

In MainPage.xaml.cs, wire up the buttons to start and stop the agent:

private const string TASK_NAME = "MyAgent";

private void StartButton_Click(object sender, RoutedEventArgs e)
{
    StartAgent();
}

private void StopButton_Click(object sender, RoutedEventArgs e)
{
    StopAgentIfStarted();
}

private void StartAgent()
{
    StopAgentIfStarted();

    PeriodicTask task = new PeriodicTask(TASK_NAME);
    task.Description = "This is our custom agent for Day 25 – Background Agents";
    ScheduledActionService.Add(task);
#if DEBUG
    // If we’re debugging, attempt to start the task immediately
    ScheduledActionService.LaunchForTest(TASK_NAME, new TimeSpan(0, 0, 1));
#endif
}

private void StopAgentIfStarted()
{
    if (ScheduledActionService.Find(TASK_NAME) != null)
    {
        ScheduledActionService.Remove(TASK_NAME);
    }
}
 

 

Notice that to create our custom agent, we are creating a new PeriodicTask. We then use the name as an identifier when finding and stopping the agent. Notice also that we specified PeriodicTask.Description – this is a required field and will appear in Settings | Background Tasks under the name of our application.

Create the Background Agent

In the MyAgent project, open ScheduledAgent.cs and add the following code:

protected override void OnInvoke(ScheduledTask task)
{
    UpdateAppTile(GetLastUpdatedTimeMessage());
}

private string GetLastUpdatedTimeMessage()
{
    return string.Format("Last Updated: {0}", DateTime.Now);
}

private void UpdateAppTile(string message)
{
    ShellTile appTile = ShellTile.ActiveTiles.First();
    if (appTile != null)
    {
        StandardTileData tileData = new StandardTileData
        {
            BackContent = message
        };

        appTile.Update(tileData);
    }
}
 

ScheduledAgent has one important method to override – OnInvoke. This is where your agent will execute its background task. If your task is complete and you no longer need your agent to run, you can call NotifyComplete() to signal that the task completed successfully or Abort() to signal that you are cancelling your task. To keep the task running at an interval, simply do not call either, which is what we are doing here.

Running the Application

Now that our application is ready to go, deploy it to the device emulator or Windows Phone and run the application. Click the button to start the background agent. Leave the application and find it in your list of applications. Tap and hold on the application and choose “pin to start”. When you view the tile on your start page you should eventually see the application tile flip around, revealing the last time it was updated.

clip_image005

Summary

So, today we created our own custom Background Agent that updates a live tile. When making Background Agents of your own, keep in mind what we covered:

  • Background Agents allow you to execute custom code while your application is not running
  • There are two types of Background Agents – Periodic and Resource Intensive
  • Periodic tasks are for tasks that have low resource consumption, and as a result have fewer restrictions than Resource Intensive tasks
  • Background Agents need their own project, which should be added as a project reference to the application that will start the agent
  • In your agent you need to override OnInvoke()
  • When your task is completed you need to call NotifyComplete() or Abort()

To download a complete Windows Phone project that uses all of the code and concepts from above, click the Download Code button below:

download

Tomorrow we are going to look at another multitasking feature called Background File Transfer that will allow us to download or upload files while our application is not running.  See you then!

toolsbutton

31 Days of Mango | Day #24: Performance Analysis

Day24-ProfilerToolDay23-ExecutionModelDay22-AppConnectDay21-SocketsDay20-Ringtones

This article is Day #24 in a series called 31 Days of Mango, and was written by guest author Chris Koenig.  Chris can be reached on Twitter at @chriskoenig.

Performance is an important aspect of all applications, especially apps that run on resource constrained, network reliant mobile devices. As a user, it is relatively easy to tell when a running application is “slow”; what is not so easy is identifying the cause of the performance problems. Making changes to the source code without understanding the effect on performance can lead to unnecessary refactoring and potentially make the problems worse.

What to do? With the release of Windows Phone “Mango”, we can now easily identify the source of our application’s performance problems – all the way down to the functions that are causing the issues. Enter the Windows Phone Profiler tool. You can use the new Windows Phone Profiler to help identify issues with performance in your application including memory consumption, visual tree complexity, application launch time, and identifying long-running functions.

To run a performance analysis session, open your Windows Phone Project in Visual Studio and select “Start Windows Phone Performance Analysis” from the Debug menu, or press the ALT-F1 shortcut key:

image_thumb

Be sure that you are launching the Windows Phone profiler, and not the .NET profiler, which is also found on the Debug menu, listed as “Start performance analysis (ALT-F2)”.

The first thing you’ll see is a page asking you to select the type of analysis you want to do. Unless you know specifically that there is a memory consumption problem, you should always start with the Execution analysis:

image_thumb1[1]

Clicking the “Launch Application” link will start up your application on either the emulator or the device with all the monitoring code automatically added to your session. Once the application is started, navigate around your application exercising those features of your application that are the most performance-critical or that are going to be most frequently used by your users. As you put your application through its paces, tracing information will be be automatically collected and recorded by Visual Studio for later review.

Once your testing session is complete, switch back over to Visual Studio and click the “Stop Profiling” link:

image_thumb1

At this point, Visual Studio will save all the performance profile data into a .SAP file and add that file to your project. This file will be keyed to your project, as well as the execution date and time of the test (e.g. DatabaseForMango_2011_11_14_17_59_27.sap”. This recording can be reviewed now, or saved for later viewing. The main view of the results is the set of graphs that are provided. These graphs represent a number of different measurements that are all stacked on top of each other to provide a timeline-based view of your applications performance.

image_thumb5

Starting at the top, these graphs show

  • Frame Rate: This shows the recorded frame rate for each frame rendered in the UI. Low numbers here are potential trouble spots that warrant more investigation.
  • CPU Usage %: Shows CPU usage across different parts of the application
    • Green bars represent the UI thread – this is the one to watch as high usage of the UI thread causes the UI to become unresponsive to user input. Any value over 50% is a potential problem area.
    • Blue bars represent the Application threads – this includes and user-created background threads and the composition thread (higher is better, compared to UI thread)
    • Grey bars represent System threads – these are the threads that are NOT part of your application, but represent things like background tasks, etc.
    • White bars represent Idle threads – like the “System Idle Process” shown in Windows Task Manager, this represents the available CPU percentage. A higher number means a more responsive UI.
  • Memory Usage in MB: Watch this if you get more than 90MB anywhere and run the other test – 90MB is the limit for passing marketplace certification.
  • Storyboards: an S is displayed at each frame where a Storyboard is launched.
    • Red represents a CPU-bound storyboard (these are bad as they run on the CPU thread and directly impact UI performance)
    • Purple represents a GPU-bound storyboard (these are good as they’re run on the Compositor thread and do not affect UI performance).
  • Image Loads: An “I” will show up on the frame to indicate where an Image is being loaded into memory.
  • Garbage Collection Events: A “G” will show up to indicate a point at which the Garbage Collector is run.

To see the details of the data that is feeding the graph you simply use the mouse to select a region of the graph containing those frames that you want to drill down into. The lower section, referred to as the Detailed Performance Analysis section, will populate with Warning and Informational messages that highlight areas of concern for the selected frames:

image_thumb3

From this picture, you can see that two specific warnings are called out related to frame rate problems. For example – the first warning in the picture above contains the following information:

Warning: Very low frame rate potentially caused by a high layout cost.
Total layout time (0.35 seconds) is high. Element System.Windows.Controls.ScrollViewer : ScrollViewer took the most time in layout and is contributing to the low frame rate. This could be because CPU-bound animations are causing layout updates. Go to the Performance Warnings menu in the navigation toolbar and select the Frames view. Sort the frames by clicking the CPU Time column header and select the frames with the highest CPU time. From the Frames view, select the Visual Tree option and identify visual System.Windows.Controls.ScrollViewer : ScrollViewer in the tree.

This warning calls out the low frame rate based on how the layout is constructed relative to the ScrollViewer. The suggested action indicates that we should drill into the Performance Warnings menu and select the Frames view. If you look closely at the Detailed Performance section, you’ll see that right next to the Performance Warnings item is a button that controls a pop-up menu containing several choices beneath it into which we can “drill down” for more information. If you choose the “Frames” option, you will see something like this:

image_thumb4

This list of the actual frames selected shows that many of them have a CPU usage well over 50% – in this case there is even one with over 80%! Selecting that frame, and going back to the navigation menu next to the Frames item from before, shows that there are still more levels of detail we can get to for that particular frame. Select each one of the items to get further information about what’s going on with that particular frame. Looking at items such as the Functions option will allow you to see what methods are being called in your application, and will provide links back to your source code for those methods from the application that are being executed. You can also look at the Visual Tree, Element Types and Cache Updates. These error messages, combined with the direct guidance given on where to look for problems and the tool’s ability for you to drill down into the root cases gives you a great viewport into your application to discover potential trouble spots and fix them before submitting to the marketplace for certification.

Now that we’ve seen how the tool works, here are a couple of tips for using it that will help speed you on your way to a speedier application:

  • Start with the Execution Performance tests to see if there are any memory issues, as indicated by the Memory Usage graph. If you discover spots where your application is consuming over 90MB of memory, run a second test focusing specifically on the Memory settings. You’ll normally find that any performance issues can be diagnosed with this first test, so only use the second test when memory concerns warrant it.
  • Don’t forget to test Fast Application Switching, Tombstoning and the corresponding Activation processes – these are all important parts of your application. To force tombstoning in your application when you press the start button, go into the project properties under the Debug tab and check “Tombstone upon deactivation while debugging”. Otherwise, your app will default to FAS.
  • Always performance test on a device – the performance of your laptop will not compare to the performance of your device. This goes back to the old “we’re not shipping this app on your laptop” axiom of testing. The Windows Phone device is much more resource constrained than the typical development workstation, so memory and performance issues will be more likely on the device than on the emulator. Running these tests against the device works the same way as traditional debugging on the device – just change the Deployment Target from “Windows Phone Emulator” to “Windows Phone Device” up in the Standard Visual Studio Toolbar.

Summary

Here are some links to additional resources on Windows Phone Performance Analysis:

Tomorrow, Gary Johnson will be writing about Background Agents, and how we can use this new feature of Windows Phone 7.5 to execute code even when our application isn’t running.  See you then!

toolsbutton

31 Days of Mango | Day #23: Execution Model

Day23-ExecutionModelDay22-AppConnectDay21-SocketsDay20-RingtonesDay19-AddingTiltEffects

This article is Day #23 in a series called 31 Days of Mango, and was written by guest author Samidip Basu.  Samidip can be reached on Twitter at @samidip.

Let’s just agree – our smartphones are pretty smart these days. But all the emails, social integration, games & applications do take a toll on the smartphone’s comparatively tiny processing system & memory, but more importantly battery life. It is thus crucial for any mobile OS & third-party applications to be very responsible in optimizing the use of resources in a smartphone, so as to provide the most fluid, responsive, yet lasting user experience. This is where Execution Models come into play & it becomes important to understand the various states/events during an application’s lifecycle. In this article, we talk about what the Execution Model looks like for Windows Phone & what has changed in the Mango release for consumers/developers.

The Windows Phone Way

As we dance between various parts of the Windows Phone OS & third-party applications all day, the phone takes a well-defined approach to managing the lifecycle of applications from launch to termination. The execution model simply allows only one application to run in the foreground at any time. While we shall see how this is beneficial to the user experience, let me play devil’s advocate & argue for the contrary. However, even if it was possible, can you really envision running multiple applications side-by-side in the foreground in a Windows Phone? Isn’t the screen real estate too limited to try doing that? The focus on one application at the foreground simply makes sense for the phone form factor and engages the user in a chrome/distraction free immersive experience. Where this is more real estate to play with, similar Metro UI operating systems do allow multiple foreground applications to be docked side-by-side, as in Windows 8 snapped views. But I digress J

So, this decision of one application on the foreground does have implications on the lifecycle of an application. Most Windows Phone users are very used to quickly moving between 3rd-party applications & the OS itself through the use of Start/Back buttons, Tiles & Toasts etc. Each Windows Phone application goes through several phases, each exposing events, as we cycle through the application’s time in the foreground. Details follow.

The Application States

In essence, each Windows Phone application cycles through the following states:

  • Running – This is the foreground primetime for any application. The OS & the user give the application all the attention to carry out what it does.
  • Dormant – The moment an application steps out of the foreground, it immediately goes into a Dormant stage. This is a new enhancement in Windows Phone Mango, where the whole application with its state & backstack history is kept intact in memory. The goal here is satisfy the supreme responsiveness of applications on resume, which have just fallen out of the foreground, in case the user wants to return to the application. This is what we call Fast Application Switching (FAS) in Windows Phone Mango.

Want to try it? Well, needless to say, you need a Windows Phone running Mango or the latest Emulator. Jump between several parts of the OS or through multiple 3rd party applications, then hold down the Back button .. and voila! You see something like this, don’t you?

FAS

What you are seeing is the Application backstack, an in-memory footprint of applications that are in Dormant state, ready to spring back to the foreground on your one tap. To the consumer, this is multi-tasking. To you as a developer, this is FAS .. a very quick application resume without you having to do anything! Well except for recompiling your pre-Mango applications using the latest Windows Phone SDK 7.1. This immediately has two effects – your application doesn’t show the old “Resuming …” message if coming back to foreground from Dormant state & you also see the application screenshot in the Application backstack. We shall see some code in a bit.

  • TombstonedNow, as we saw, the Windows Phone runtime keeps a backstack of in-memory Dormant applications that have recently been on the foreground. While the instant resume is great, any smartphone has limited memory availability and the OS might need support to pull off an expensive operation. Guess what happens next .. yep, applications fall off the backstack in Last-In-First-Out mode! In other words, they are tombstoned & considered to be not consuming any system resources beyond that point. The last statement is technically not entirely true, as we shall see in a minute.

So, how does Tombstoning affect an applications lifecycle? Well, if the user has been using your application, and then went on to a few very resource-intensive games, there is a chance that eventually your application might be tombstoned to release some memory back for system consumption. However, the user might decide to traverse the backstack to get back into your application after a while. How should your application behave? Can we remember things the user was up to when he/she left our application?

The answer is yes! We can absolutely provide the user with an experience that might come across as if he/she never really left your application & start from where they left off. To achieve this effect, however, needs us developers to share some responsibility to manage the state of our application throughout its lifecycle. In the code that follows, we shall see how we can hydrate our application state when resuming an application out of Tombstone, to give the end user the impression that the application never actually got killed. The truth is even when an application in Tombstoned, some little data (as a dictionary) about the state of the application and backstack of pages within the application is preserved in memory by the Windows Phone OS.

  • Terminated – An application in this state has absolutely zero memory footprint on the Windows Phone OS. Nothing, including State dictionaries, which we talk about later, is preserved and any subsequent use of the application results in a fresh instance. An application reaches this stage after it has been Tombstoned or the user back-navigated past the first page or there was an unhandled exception killing the application.

Pages & Events

Before we move on to application lifecycle events, let us take a small step back to make sure our fundamentals are right. All Windows Phone Silverlight applications run as a collection of XAML pages that are loaded inside a Phone Application Frame. While the application is in the foreground, the user is free to navigate between pages inside the application. Hitting the phone’s Back button makes the user traverse through a backstack of pages inside an application, until the first page of the application is hit & then next Back key press exits our application. We, as developers, need not do anything to make this happen, as the Windows Phone OS takes care of this automatically during the application’s primetime in the foreground.

But consider this .. a user is typing some content in a text input control on one XAML page, gets distracted & actually moves out of our application to carry out some operation. When he comes back, two things might happen. One, the application could have just been Dormant & springs right back into foreground, retaining the exactly what the user was typing .. there is nothing your application needs to do to support this, except for checking on an API to make sure you application was Dormant. Secondly, your application may have been Tombstoned & now you have a little problem. You need to bring your application back to life & hydrate the state of the XAML page to exactly how the user left it .. this we shall see in code.

So, now that we are talking Page States, it is a good time to talk about two events during a page’s own life span:

  • OnNavigatedTo – This event fires when the page is being brought to the foreground for display. This provides us developers an opportunity to read query strings passed into the page or hydrate the page controls appropriately if coming out of Tombstone.
  • OnNavigatedFrom – This event fires when the user is leaving the present page to go to another page within the application or leaving the application altogether. In either case, this serves as a good checkpoint to save any state information for the current page, in case restoration may be needed in future. We shall see examples in code.

Data & State Dictionaries

Now, let’s take a look at what kind of data we are trying to preserve & hydrate/dehydrate during our application’s Execution Model. In my opinion, application data on Windows Phone is of two types:

  • Settings & Permanent Data – This type of data is the crux of your application and needs to be persisted across application runs/instances. We should waste no time in saving such data straight to Isolated Storage, either as Name/Value pairs or Files/Directories, or in SQL CE if the data is relational.
  • Page & Transient Data ­– This is the expendable, but convenient to save data & is mostly dealt with in memory. This type of data could be anything ranging from user-entered unsaved data on a page or some ViewModel or some temporary data per application lifecycle, fetched from outside. This is the data we need to handle carefully to give the end users an impression that our application is alive & kicking throughout its lifecycle. Now, we have some help. Windows Phone OS exposes a Dictionary to each application & each application page that could be used to store serializable Key-Value pair data. This State dictionary is off of the PhoneApplicationService and should only be used to store transient state data. You should not use this property for excessive storage because there is a limit of 2 MB for each page and 4 MB for the entire application; but as we shall see in code, this is rather helpful in maintaining state during our application’s execution model. And it is these dictionaries that are persisted by the Windows Phone OS even after our application has been tombstoned. If the application is reactivated from Tombstone, this state dictionary will be populated with the data we saved in it during application’s Deactivation. Because this data is present in memory, we can use it to restore state without resource-intensive file operations.

Application Events

Now that we know all the details & the inside workings, let’s just see when we do what during an application’s lifecycle. The PhoneApplicationService raises 4 primary events during an application’s execution model that helps us manage state:

· Launching – This event is raised when a new application instance is created by user actions like launching from application list, or by tapping on Tile/Toast or other means. In this case, we begin with a fresh slate, and not as any continuation of past application lifecycles.

· Deactivated – This event is raised when the users navigates away from our application or a Chooser is launched. This is the best opportunity for us to save the state of the application into the State dictionary for future use in resuming the application. If resumed from Dormant state, this would not be necessary; but absolutely needed if resuming from Tombstone and the Deactivated event is the only chance we shall get to save application-level state.

· Activated – This event is fired when the application is returning to the foreground, either from being Dormant or Tombstoned. Guess what .. a simple API flag called the IsApplicationInstancePreserved off of the event args tells us what state our application is resuming from. If the flag is true, our application has just been Dormant & held in memory; so no action is required and FAS kicks in. If the flag is false, we are returning from Tombstone & would use the state dictionary to restore application state.

· Closing – This event fired when the user traverses through the application’s page backstack & past the first application page. At this point, the application should have exited the foreground & terminated itself after raising an event. No state information is preserved on termination and subsequent launches of the application would result in fresh instances.

As a common theme, heavy resource intensive tasks should be avoided during any of the above application events, since we have a limited amount of time (10 seconds to be precise) that the OS would wait for our methods to finish. For best user experience, some of the expensive operations of maintaining state should be performed on background threads while the application is running.

Want to make sense of all of the above information? Well just take a look at the overall Execution Model diagram for Windows Phone, best described by an MSDN article:

Execution Model

[Courtesy MSDN]

Demo Application

We have been all-talk so far, haven’t we? Let’s see some code! We’re going to build a simple Windows Phone application that highlights state management across the application’s lifecycle. The entire built application is available for download at the end of the article; just make sure you have Windows Phone SDK 7.1, grab the bits & hit F5!

So, let’s begin. File -> New & we accept the most basic default template for an application with one XAML page only, that being MainPage.xaml/cs. We are going to open up the XAML page & drop some demo controls for our sake. The end state is something like this (click to enlarge):

XAML Page

Here’s the goal .. we are going to split up the controls to manage states of various types of data, as described below:

  • App Setting – This is an example of an application level setting that has to be persisted across application instances. Most common example would be a user setting for your application.
  • App Transient Data – This set of controls will simulate application level data that is only applicable per application instance, but may be usable in multiple XAML pages throughout the application. Best such example would be some web service data that an application fetches every time it runs afresh.
  • Page Transient Data – This set of controls stands for page specific control data that we possibly do not want to lose if the user steps out of our application & comes back to it through application backstack.

We’re going to handle each type of data separately. So, let’s start with the App.xaml.cs – the place to handle global application logic/data. Let’s add some custom properties/initializers, along with a little code in the Constructor:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;

using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Day_24___Execution_Model
{
    public partial class App : Application
    {
        public PhoneApplicationFrame RootFrame { get; private set; }

        public bool AppSetting { get; set; }
        public string AppData { get; set; }

        public static new App Current
        {
            get { return Application.Current as App; }
        }

        // Constructor.
        public App()
        {
            // All other initialization code ..
            AppData = string.Empty;

            if (IsolatedStorageSettings.ApplicationSettings.Contains("AppSetting"))
            {
                AppSetting = (bool)IsolatedStorageSettings.ApplicationSettings["AppSetting"];
            }
        }
    }
}
 

 

Next, we’re going to add some code to application’s lifecycle event handlers. Notice the use of the IsApplicationInstancePreserved flag to decide whether we are coming out of Dormant/Tombstoned state in the application’s Activated event handler. Now, I didn’t have a good reason to add any special code to the application’s Launching/Closing event handlers; but you are free to if your application needs any such code. Also, notice the use of the State dictionary off the PhoneApplicationService:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;

using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Day_24___Execution_Model
{
    public partial class App : Application
    {
        public PhoneApplicationFrame RootFrame { get; private set; }

        public bool AppSetting { get; set; }
        public string AppData { get; set; }

        public static new App Current
        {
            get { return Application.Current as App; }
        }

        // Constructor.
        public App()
        {
            // All other initialization code ..
            AppData = string.Empty;

            if (IsolatedStorageSettings.ApplicationSettings.Contains("AppSetting"))
            {
                AppSetting = (bool)IsolatedStorageSettings.ApplicationSettings["AppSetting"];
            }
        }

        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
        }

        private void Application_Activated(object sender, ActivatedEventArgs e)
        {
            if (e.IsApplicationInstancePreserved)
            {
                // Returning from Dormancy.
                // Do nothing.
            }
            else
            {
                // Returning from Tombstone.
                if (PhoneApplicationService.Current.State.ContainsKey("AppData"))
                {
                    AppData = PhoneApplicationService.Current.State["AppData"].ToString();
                }
            }
        }

        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            PhoneApplicationService.Current.State["AppData"] = AppData;
        }

        private void Application_Closing(object sender, ClosingEventArgs e)
        {
        }

        // Other auto-generated code here ..
    }
}
 

 

Now, back in our MainPage.xaml’s code-behind, let’s add event handlers for the page’s loading event & the click of the button to fetch some data (which we totally fake), as well as the application setting checkbox’s state being changed. Notice how we hang on to the fetched data at the application level and also how we immediately save application/user settings in the phone’s Isolated Storage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;

using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Day_24___Execution_Model
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor.
        public MainPage()
        {
            InitializeComponent();
        }

        private void chkAppSetting_Tap(object sender, GestureEventArgs e)
        {
            // Store App Setting changes immediately in Isolated Storage for persistence.
            if (IsolatedStorageSettings.ApplicationSettings.Contains("AppSetting"))
            {
                IsolatedStorageSettings.ApplicationSettings.Remove("AppSetting");
            }

            if ((bool)this.chkAppSetting.IsChecked)
            {
                IsolatedStorageSettings.ApplicationSettings.Add("AppSetting", true);
            }
            else
            {
                IsolatedStorageSettings.ApplicationSettings.Add("AppSetting", false);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.txtAppData.Text = "This is some sample data ..";

            // As if we are caching the data.
            App.Current.AppData = this.txtAppData.Text;
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            this.chkAppSetting.IsChecked = App.Current.AppSetting;
        }
    }
}
 

 

Now, let’s add the all-important page navigation events. This is where we get to control how we hydrate/dehydrate transient data as the XAML page comes to the foreground & moves out of it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.IO.IsolatedStorage;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace Day_24___Execution_Model
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor.
        public MainPage()
        {
            InitializeComponent();
        }

        private void chkAppSetting_Tap(object sender, GestureEventArgs e)
        {
            // Store App Setting changes immediately in Isolated Storage for persistence.
            if (IsolatedStorageSettings.ApplicationSettings.Contains("AppSetting"))
            {
                IsolatedStorageSettings.ApplicationSettings.Remove("AppSetting");
            }

            if ((bool)this.chkAppSetting.IsChecked)
            {
                IsolatedStorageSettings.ApplicationSettings.Add("AppSetting", true);
            }
            else
            {
                IsolatedStorageSettings.ApplicationSettings.Add("AppSetting", false);
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Fake data fetch..
            this.txtAppData.Text = "This is some sample data ..";

            // As if we are caching the data.
            App.Current.AppData = this.txtAppData.Text;
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Load user setting from Isolated Storage.
            this.chkAppSetting.IsChecked = App.Current.AppSetting;
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            // Load in App Data, if available.
            if (App.Current.AppData != null && App.Current.AppData != string.Empty)
            {
                this.txtAppData.Text = App.Current.AppData;
            }

            // Load any Page State, if available.
            if (PhoneApplicationService.Current.State.ContainsKey("PageData"))
            {
                this.txtPageData.Text = PhoneApplicationService.Current.State["PageData"].ToString();
            }
            if (PhoneApplicationService.Current.State.ContainsKey("PageSetting"))
            {
                this.chkPageSetting.IsChecked = (bool)PhoneApplicationService.Current.State["PageSetting"];
            }
        }

        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

            // Clear past state, if any.
            if (PhoneApplicationService.Current.State.ContainsKey("PageData"))
            {
                PhoneApplicationService.Current.State.Remove("PageData");
            }

            if (PhoneApplicationService.Current.State.ContainsKey("PageSetting"))
            {
                PhoneApplicationService.Current.State.Remove("PageSetting");
            }

            // Save off Page state.
            PhoneApplicationService.Current.State["PageData"] = this.txtPageData.Text;
            PhoneApplicationService.Current.State["PageSetting"] = this.chkPageSetting.IsChecked;
        }
    }
}
 

That’s it! We have now added enough code so that the different types of data/state are managed across the lifecycle of the application, each in a different way as appropriate. Go ahead & give it a spin. Start the application, make setting changes, go somewhere else & come back, or exit & run fresh instance of the application. Data & state information should be preserved and wiped as expected. A typical run with settings turned on looks something like this:

App and Page State

Now, you might notice one thing on both the emulator or if deployed to an actual phone. As we cycle through the application, step out & then return to it in the Windows Phone Mango runtime, it is hard to predict when our application would actually be tombstoned. Most times, if deactivated, the application simply sits in Dormant state & comes right back to life. So, although we have code to hydrate settings when coming back from Tombstone, there is not definite way to test it.

Worry not! There is a simple debug setting that is going to forcibly tombstone your application the moment it deactivates. So, even if the application can stay Dormant, this setting, shown below, forces it to be tombstoned. This obviously helps our testing.

Tombstone Setting

Summary

Adding breakpoints to various event handlers and seeing when they fire during an application’s lifecycle, is a great way to understand the Execution Model. So, what are you waiting for? Go ahead and make full use of the Fast-Application-Switching and hydrate/dehydrate your application/page state correctly throughout the lifecycle of the application.

Result – Happy users, and ultimately happier you!  Adios!

To download a complete Windows Phone project that includes all of the concepts covered in this article, click the Download Code button below.

download

Tomorrow, Chris Koenig is going to talk about another great tool available to us in Visual Studio 2010, the Silverlight Performance Analysis Tool.  See you then!

toolsbutton

31 Days of Mango | Day #22: App Connect

Day22-AppConnectDay21-SocketsDay20-RingtonesDay19-AddingTiltEffectsDay18-ExpressionBlendSampleData

This article is Day #22 in a series called 31 Days of Mango, and is written by guest author Matt Eland.  Matt can be reached on Twitter at @integerman.

What is App Connect?

Windows Phone Mango introduces a multitude of fantastic improvements to the already great Windows Phone operating system. Among these enhancements are number of improvements to the Bing search engine on the phone. While many of these features such as visual search and turn by turn directions are intended for customers, Microsoft also introduced a few features aimed at allowing developers to integrate apps into the search results either via Instant Answers, a way of highlighting apps relevant to specific searches, or via a new feature in Mango called Quick Cards.

Quick Cards are items that appear in certain searches that allow users to find out more about certain products, locations, or movies within Bing. Pictured below is an example of search results that include Quick Cards for several books matching the user’s search:

clip_image002

Clicking on one of these items navigates you to that product’s Quick Card which allows you to find more information on a product in a centralized location as pictured below:

clip_image004

App Connect is another new feature in Windows Phone Mango that allows apps to be listed on the apps pivot item on Quick Cards that are relevant to an app’s subject matter. From there, the user can click and launch the app and be met with an app launch experience that can be custom tailored to the Quick Card the user just came from.

It’s important to note that presently only the United States supports product and movie Quick Cards though place Quick Cards are more widely available. Despite this present limitation we will also touch on localizing search result text.

See http://msdn.microsoft.com/en-us/library/hh202957(v=VS.92).aspx#BKMK_AppConnect for a more detailed and up-to-date list on the types of Quick Cards that are supported.

Similar to Quick Cards, developers can also have their apps be aware of scenarios where they are launched as by Bing Instant Answers, another Mango improvement to Bing search. Bing Instant Answers allows Bing to feature certain apps that it thinks are highly relevant to a specific search.

For this article we will be creating an app that allows you to quickly search for a book on an online retailer’s site by taking advantage of search extensibility integration for Quick Cards for books and magazines and providing a customized experience if it was launched from Bing Instant Answers.

Getting started with search extensibility

Setting up your app to take advantage of App Connect is relatively easy though there are a number of steps you’ll need to follow in order to get things working.

We’ll start by creating a new Visual Studio Windows Phone Application project targeting Windows Phone 7.1.

Registering search extensions

In order for Windows Phone to know that your app supports App Connect, you need to add an entry to the manifest file telling the phone what search extensions the app supports. This is important and should only include product types that are relevant to your application.

Expand the properties node of the project file and go into WMAppManifest.xml. This is the phone’s application manifest for the marketplace and defines all relevant information for your application. You’ll need to add a new node inside of the App element as illustrated in the following file:

<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.1">
    <App ="" >
        <IconPath IsRelative="true" IsResource="false">ApplicationIcon.jpg</IconPath>
        <Capabilities></Capabilities>
        <Tasks>
            <DefaultTask Name ="_default" NavigationPage="MainPage.xaml"/>
        </Tasks>
        <Tokens></Tokens>
        <Extensions>
            <!– Beta extension, for development and testing only –>
            <Extension ExtensionName="Products"
            ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5661}"
            TaskID="_default"
            ExtraFile="Extensions/Extras.xml" />
            <!– Production extensions, for submission to Marketplace –>
            <Extension ExtensionName="Bing_Products_Books_and_Magazines"
            ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5661}"
            TaskID="_default"
            ExtraFile="Extensions/Extras.xml" />
        </Extensions>
    </App>
</Deployment>
 

The important aspect of this is the two Extension elements. ExtensionName identifies which Quick Card the extension supports integration with. See http://msdn.microsoft.com/en-us/library/hh202958(v=VS.92) for a complete list of available Quick Cards.

The emulator handles App Connect differently than the final version Mango that runs on phone. In the emulator all product Quick Cards have a category of “Products” instead of the more specific individual ExtensionNames. That is to say that if we registered our app to support books and magazines by using the “Bing_Products_Books_and_Magazines” ExtensionName, our app would show up as supported for a book Quick Card on the device but not on the emulator and if we registered as only supporting the “Products” category, the app would appear to work fine in the emulator but would not work properly on actual devices. Because of this you’ll want to support both the broad “Products” category as well as any specific categories you may want to handle by defining multiple Extension elements.

The other fields in the Extension element are relatively simple to deal with: ConsumerID identifies search extensibility as the feature the extension maps to and should not be changed. TaskID specifies the task that should be launched when the extension is triggered. ExtraFile tells the app where to look for the extra data needed to support search integration and must point to Extensions/Extras.xml or App Connect will not work.

Configuring extra data needed by App Connect

Since our project doesn’t contain the Extensions/Extras.xml we referenced in the two extensions we registered we’ll have to create it. Right click on the project in the solution explorer and click “Add -> New Folder”, rename the folder to “Extensions”, right click that folder and select “Add -> New Item”. Select XML File from the list and name it Extras.xml. The name and path of this file must be exact or search extensions will not function properly.

clip_image006

You should now have an Extras.xml file in the Extensions folder. From here we’ll need to add an ExtrasInfo node to the xml file that defines how the app behaves with the extensions we registered.

<ExtrasInfo>
    <AppTitle>
        <!– Neutral language application title. –>
        <default>Book Helper</default>
        <!– Localized titles –>
        <es-ES>Libro Helper</es-ES>
        <fr-FR>Livre Helper</fr-FR>
        <zh-CN></zh-CN>
    </AppTitle>
    <Consumer ConsumerID="{5B04B775-356B-4AA0-AAF8-6491FFEA5661}">
        <ExtensionInfo>
            <Extensions>
                <!– Corresponding product extension for books –>
                <ExtensionName>Bing_Products_Books_and_Magazines</ExtensionName>
                <!– Beta extension, for all products. –>
                <ExtensionName>Products</ExtensionName>
            </Extensions>
            <CaptionString>
                <!– Neutral language caption –>
                <default>Search vendors for books and eBooks</default>
                <!– Localized captions –>
                <es-ES>Bsqueda de libros y libros electrnicos de varios proveedores</es-ES>
                <fr-FR>Recherche de livres et eBooks provenant de divers fournisseurs</fr-FR>
                <zh-CN></zh-CN>
            </CaptionString>
        </ExtensionInfo>
    </Consumer>
</ExtrasInfo>
 

The AppTitle element and its children tell Windows Phone what to call our application (and provide some localized strings for different locales). The default node inside of this is used if a locale-specific string cannot be found and should represent the app’s title in the assembly’s neutral language. Additional nodes can be added with names matching the culture code that the localized string is for. For example, es-ES in this example indicates the string used in Spanish language settings.

The Consumer node has a ConsumerID that matches the ConsumerIDs we registered in the WMAppManifest.xml file earlier. Inside of this node is an ExtensionInfo node with an Extensions node that contains ExtensionName elements that define the extensions we said we supported.

The CaptionString element defines the message used next to the search extension’s tile and is localized the same way the AppTitle element is. An example of this app showing up as a search extension is pictured below:

clip_image008

Note that the application’s icon is used for this image and the background could be either light or dark depending on the theme. Consequently, transparency on app icons should not be used when App Connect integration is present. Additionally, the pivot item for App Connect on Quick Cards in the emulator says “extras” while in actual Mango devices this pivot item is labeled “apps”.

If you need to specify different captions for different types of products, you can do so by declaring multiple ExtensionInfo elements and using some ExtensionName elements in one ExtensionInfo element and others in another as long as all ExtensionNames you say your app supports are represented in an ExtensionInfo.

Setting up URI mapping

When a user enters the app using App Connect the runtime will attempt to navigate to the /SearchExtras URI. In order to support this entry point we’ll need to set up some URI mappings to redirect traffic to the appropriate page. To do this, we’ll define a UriMapper resource in the Application’s resources collection by going into App.xaml and adding the following resource to Application.Resources:

<Application.Resources>
    <nav:UriMapper x:Key="UriMapper" xmlns:nav="clr-namespace:System.Windows.Navigation;assembly=Microsoft.Phone">
        <nav:UriMapper.UriMappings>
            <nav:UriMapping Uri="/SearchExtras" MappedUri="/MainPage.xaml" />
        </nav:UriMapper.UriMappings>
    </nav:UriMapper>
</Application.Resources>
 

Defining this resource isn’t enough. We need to tell the app to find and use this UriMapper for resolving requests. We do this by adding the following code to the constructor in App.xaml.cs:

// Enable URI mapping for Search Extras deep link URIs

RootFrame.UriMapper = Resources["UriMapper"] as UriMapper;
 

This will correctly map all incoming App Connect traffic to navigate to the MainPage once our application uses. If we wanted to we could specify a specific item details page in the MappedUri property that is specific to App Connect but for the purposes of this example, this will suffice.

Taking advantage of App Connect integration

At this point if you run your application in the emulator and then go to Bing search on the device using the search key, you should see your application listed on the extras pivot for a product’s Quick Card – provided you registered your app as supporting Products – individual product type mappings do not work for the emulator but will work on your actual device (and vice versa – registering as supporting the broad category of products does not work on actual devices).

Unfortunately, our app doesn’t actually do anything with the data provided by App Connect yet. To fix this, let’s start by defining our user interface. Go into MainPage.xaml and replace the Grid named LayoutRoot and all of its children with the following XAML:

<Grid Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <StackPanel Margin="12,17,0,28">
        <TextBlock Text="BOOK HELPER" Style="{StaticResource PhoneTextNormalStyle}" />
        <TextBlock Text="Welcome" x:Name="lblPageTitle" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}" />
    </StackPanel>
    <ScrollViewer Margin="12,0,12,0" Grid.Row="1">
        <StackPanel>
            <TextBlock TextWrapping="Wrap" x:Name="lblBookTitle" Visibility="Collapsed" Style="{StaticResource PhoneTextLargeStyle}" Text="Book title goes here" />
            <TextBlock TextWrapping="Wrap" x:Name="lblNoSearch" Text="To use this product, use your device’s search functions to look for a book and then select this app from the apps section." Style="{StaticResource PhoneTextNormalStyle}" />
            <HyperlinkButton HorizontalContentAlignment="Left" Foreground="{StaticResource PhoneAccentBrush}" Margin="{StaticResource PhoneVerticalMargin}" Content="Search Amazon" Click="HandleSearchAmazonBooks" />
            <HyperlinkButton HorizontalContentAlignment="Left" Foreground="{StaticResource PhoneAccentBrush}" Margin="{StaticResource PhoneVerticalMargin}" Content="Search Barnes and Noble" Click="HandleSearchBarnesAndNoble" />
        </StackPanel>
    </ScrollViewer>
</Grid>
 

This defines a user interface that will be able to function either as a stand-alone app (in case of a normal app launch) or serve as a details page if the application is launched using App Connect. By default, the application will look like the following image:

clip_image010

Handling Query Parameters

Obviously, we’d like to be able to do something special if we launched the app from App Connect on a Quick Card. Thankfully, when entering a page via App Connect, the navigation context of the page contains two query string parameters that can help us identify basic information on the Quick Card that launched the application. The ProductName query string argument will contain the name of the product that is associated with the Quick Card the user just viewed and the Category argument will be the ExtensionName that is associated with that Quick Card.

It is important to wait for the page to load before checking for query string parameters since the NavigationContext will not be available until loading is complete.

While this is fairly basic information, it is still useful for applications that need to pre-populate fields or controls with product names or for pages that need to be flexible enough to handle multiple types of products. Bear in mind that for debugging purposes Category will always be “Products” in the emulator but will have the correct values when run on an actual device.

For our sample app, we’ll have the page display the product name in the page if we came in to the app through App Connect, but leave the existing user interface if this is handling a standard launch. Because the app launch entry point and the search extras entry point use the same page for our demo it is important to check for the existence of the query string arguments before trying to use them.

Here is the modified MainPage.xaml.cs that includes logic for parsing the query string parameters and handling hyperlink clicks:

public partial class MainPage : PhoneApplicationPage
{
    private string _book;
    // Constructor
    public MainPage()
    {
        InitializeComponent();
        // We need to wait until loaded before checking NavigationContext
        Loaded += HandleLoaded;
    }

    private void HandleLoaded(object sender, RoutedEventArgs e)
    {
        // Determine what the context of the app launch is
        if (NavigationContext.QueryString.ContainsKey("ProductName"))
        {
            _book = NavigationContext.QueryString["ProductName"];
            lblPageTitle.Text = "Book Details";
        }
        else
        {
            _book = null;
        }

        // In a "real" application we’d want to use binding and converters
        if (!string.IsNullOrWhiteSpace(_book))
        {
            lblBookTitle.Text = _book;
            lblNoSearch.Visibility = Visibility.Collapsed;
            lblBookTitle.Visibility = Visibility.Visible;
        }
        else
        {
            lblNoSearch.Visibility = Visibility.Visible;
            lblBookTitle.Visibility = Visibility.Collapsed;
        }
    }

    private void HandleSearchBarnesAndNoble(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(_book))
        {
            BrowseTo("http://www.barnesandnoble.com/ebooks/index.asp&quot;);
        }
        else
        {
            BrowseTo("http://productsearch.barnesandnoble.com/search/results.aspx?store=BOOK&keyword="&quot; + _book.Replace(" ", "+") + """);
        }
    }

    private void HandleSearchAmazonBooks(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(_book))
        {
            BrowseTo("http://www.amazon.com/gp/aw/sb.html/sn=Books&quot;);
        }
        else
        {
            BrowseTo("http://www.amazon.com/gp/aw/s/?k=&quot; + _book.Replace(" ", "+"));
        }
    }

    private static void BrowseTo(string address)
    {
        var webTask = new Microsoft.Phone.Tasks.WebBrowserTask { Uri = new Uri(address) };
        webTask.Show();
    }
}
 

Now when we launch our app through App Connect we see the following:

clip_image012

Supporting App Instant Answers

Another related feature introduced in Windows Phone Mango is App Instant Answers. This is an automatic feature of Bing search where apps Bing decides are relevant to a specific search are featured at the top of the search results. You don’t have to do anything in order to support launching from Instant Answers but you can take advantage of information passed in through this functionality if you choose. This information is exposed through a query string parameter called “bing_query” and is accessed similarly to the ProductName and Category query string parameters.

Modifying our sample app to take advantage of Instant Answers is extremely easy as illustrated by the modified top half of the HandleLoaded method:

// Determine what the context of the app launch is
if (NavigationContext.QueryString.ContainsKey("ProductName"))
{
    _book = NavigationContext.QueryString["ProductName"];
    lblPageTitle.Text = "Book Details";
}
else if (NavigationContext.QueryString.ContainsKey("bing_query"))
{
    _book = NavigationContext.QueryString["bing_query"];
    lblPageTitle.Text = "Related Search";
}
 

This modification allows the application to grab either the book title out of the Quick Card’s product name if one is present or from the Bing query that generated the Instant Answers result. The image below illustrates entering the app through an Instant Answers result for the search string “Sphere by Michael Crichton”

clip_image014

Testing App Connect

You might be wondering how to test Instant Answers or attach with a debugger when working with Search Extensions. This is a valid point since there isn’t currently a good way of influencing Bing search results using the emulator and when working with search extensions the Category attribute does not register the same as it would on the device. It also can become time consuming to navigate to Bing, execute a specific search and then launch the app using App Connect. Thankfully, there’s an easy way to simulate launching your app either through search extensions or through instant answers.

Since we can predict the query string parameters that Quick Cards will generate when entering our app, it is possible to hard code these values into the application’s entry point for testing purposes. Windows Phone apps store the default page’s address inside of the WMAppManifest.xml file in the properties node of the project. Open up this file and find the DefaultTask element inside the Tasks collection. It should look something like this:

<DefaultTask Name ="_default" NavigationPage="MainPage.xaml"/>

This element tells the application where to navigate when the application starts and can be modified to point to whatever file you desire. It can also be modified to simulate entering the app via search extensions or instant answers by specifying query string parameters. For example, the following entry was used to test Instant Answers in the section above:

<DefaultTask Name ="_default" NavigationPage="MainPage.xaml?bing_query=Sphere by Michael Crichton"/>

The modifications for simulating a search extension entry point for a similar product are very similar. Note that since we’re specifying multiple query string parameters that using &amp; to escape the ampersand is important as seen in the following snippet:

<DefaultTask Name ="_default" NavigationPage="MainPage.xaml?Category=Bing_Products_Books_and_Magazines&amp;ProductName=Sphere"/>

Of course, once you are done testing and ready to deploy the application, make sure you remove any hardcoded query string parameters from the default task so the app will function as intended.

You may occasionally run into deployment errors when making modifications to the WMAppManifest.xml file and attempting to launch the app in the emulator. If the deployment fails with the message: “Installation of the application failed. Run time error has occurred. Fix the Capabilities in WMAppManifest.xml file.” and your capabilities section looks fine, just rebuild the app and try again.

Summary

This wraps up coverage of App Connect and Instant Answers, two simple, flexible and easy to use ways to allow your app to integrate with extensibility points in the improved Bing search engine for Windows Phone Mango.

To download a complete working Windows Phone application that uses the code that was demonstrated in this article, click the Download Code button below:

download

Tomorrow, Samidip Basu is back to discuss the Execution Model of Windows Phone, including Fast App Switching, and how Tombstoning (which was covered in Day #14 of the 31 Days of Windows Phone) has changed slightly to accommodate the new 7.5 operating system.  See you then!

toolsbutton

31 Days of Mango | Day #21: Sockets

Day21-SocketsDay20-RingtonesDay19-AddingTiltEffectsDay18-ExpressionBlendSampleDataDay17-WindowsAzure

This article is Day #21 in a series called 31 Days of Mango, and was written by guest author Parag Joshi.  Parag can be reached on Twitter at @ilovethexbox.

Today we will take a peek at the new support for sockets announced in Windows Phone 7.1. So, what are sockets? Simply put it is the communication mechanism based on TCP/IP that is used for remote applications like printing, video conferencing and many more.

Before we delve into how to write a socket based windows phone application let us take time to understand what sockets is all about.

Sockets – What is involved?

Applications communicate via sockets based on a socket address. A socket address is a combination of a TCP/IP address and a port. Using this information, applications can communicate with each other over a local network or via the internet.

The article mentioned below gives a very good explanation of the terms and technology behind sockets. As a programmer, all you need to know is how to connect (if using TCP/IP) and how to send / receive data.

Sockets is a low level technology. This means that you need to determine the data that is sent and how it is read. While this can be prone to parsing errors, it gives you tremendous benefit in terms of data transfer speed over web services.

Here is a link to a detailed article on sockets and the support in Windows Phone 7.1: http://msdn.microsoft.com/en-us/library/hh202874(v=vs.92).aspx.

What are we going to do?

We are going to build a simple application for taking orders in a restaurant. There will be a windows phone 7 application for taking orders and there will be a Silverlight out of browser application for receiving/processing the orders that will run on your host desktop or laptop. The concept is that servers will take orders on the Windows Phone 7 devices and the host will receive the orders and send the status of the orders as they are done.

The servers will be notified on each order as it completes.

This application is based on the "Rock, Paper, Scissors" multicast application on msdn (http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx).

So let’s get started!

Quick overview

At the very minimum, we need to build a server application that receives the data sent by the client. For the demo we chose a Silverlight (Out of Browser) application.

Note: We have to run the Silverlight application in "Out of Browser" mode with elevated permissions so that it can access the socket data received.

We need to agree on what data is sent to the host -> a table number, order information and spice level.

/// <summary>
/// When we receive the Order, we pass on the table number and other parameters
/// </summary>

public class OrderReceivedEventArgs : EventArgs
{
    public int tableNumber { get; set; }
    public int spiceLevel { get; set; }
    public string order { get; set; }
}

We will also display the Windows Phone 7 devices connected to the host. This helps the person managing the host to know how many servers are working at a time. This information comes from the "DeviceInfo" object. Here is a snippet of the declaration:

/// <summary>
/// The information about each device. This class must implement INotifyPropertyChanged as it is
/// bound to a datagrid using an observable collection.
/// </summary>
public class DeviceInfo : INotifyPropertyChanged
{
    private IPEndPoint _DeviceEndPoint;
    private string _DeviceOrServerName;
    public DeviceInfo(string deviceOrServerName, IPEndPoint endPoint)
    {
        _DeviceEndPoint = endPoint;
        _DeviceOrServerName = deviceOrServerName;
    }
}

Here is a screenshot of the host:

clip_image002

We also need the windows phone 7 clients to take the order, a simple application which takes in the above data and submits it.

Here is a screenshot of the windows phone 7 application:

clip_image004

As you can see, we have the name of the server at the top. This is currently application generated but as an extension we can provide the user the ability to sign in and use the sign in data to show the name of the server logged in.

We have two sliders:

1. The first slider is to choose the table number. It ranges from 1 to 10. This is a very simplistic approach for table selection and will work easily for even 20-30 tables as the slider is very precise and allows for easy touch selection.

2. The second slider is to choose the spice level. It comes primarily from my taste of spicy food but is also something widely specified while ordering food.

The range is set from 1 to 10.

The third element is a textbox to put order details. If you wish to extend this demo, you can add a scrolling selection of menu items and a datagrid to add each selected menu item. For this sample we have kept it simple to a text input.

And finally we need a button to send the order. That’s it!

The following key points should be noted:

1. RestaurantCommands class: This class contains the commands allowed in our socket application and must be common to the host and the recipient to understand the message sent and received.

2. UdpAnySourceMulticastChannel.cs and UdpPacketReceivedEventArgs.cs: These are two files we have taken from the sdk multicast application that contain the UDP multicast sockets code for joining the group, sending and receiving data.

3. Order class: This class handles all application communication. Communication for the application is made up of a number of commands that we have defined in the RestaurantCommand.cs class. These commands are the grammar, or set of actions, that we can transmit and receive and interpret.

Understanding the sample

Prerequisites: Install the Mango tools from http://create.msdn.com. This should give you Visual Studio Express 2010 and the Windows Phone SDK that you need to develop applications for Windows Phone. We are also running a Silverlight application on the host. Download Visual Studio c# express edition to get the required templates.

  • Launch Visual Studio and browse to the solution file and open it.
  • Note: The solution file has two startup projects. The "TakeMyOrder" windows phone 7 project and the "PointOfSaleApp" Silverlight application.
  • This is a multicast socket sample. To run this you need to deploy the windows phone 7 sample to the phone and run the Silverlight application on host.
  • Alternatively, if you do not have a phone, deploy the Silverlight application to another machine (say a Virtual Machine) and run the Windows Phone 7 app in an emulator on the host.
  • You cannot run the Silverlight application and the windows phone 7 application on the emulator on the same machine.
  • If you have multiple machines, phones, you can run the windows phone 7 application simultaneously on all of them. This will give you a feel for multiple servers taking orders and submitting them at the same time.
  • Since we are using UDP protocol, there is no guarantee that the messages sent are received. This is due to the fact that there is no peer to peer connection between two devices. Instead devices join a multicast group identified by an ip address and a port. However as you will see when you run the application, the communication is fairly reliable.

How it works:

  • Launch the Silverlight out of browser application.
  • Launch the windows phone 7 application on the phone or on an emulator running on another machine.
  • The host will show the name of the server and the end point address.
  • At this point you are ready to place an order.
  • On the windows phone 7 application, Use the table slider and choose a table from 1 to 10.
  • Enter an order. E.g. Fried rice with chicken and shrimp. Coke no ice etc.
  • Use the spice slider to set a spice level desired. 10 would be an excellent choice!
  • Click Order. At this point the windows phone 7 application sends the "SendOrder" command to all the devices on the group. Alternatively we could have filtered this to just send the order to the host.
  • On the host, the order is received and added to the "Incoming Orders" grid. This shows up with a status of "In Process" and a unique order id (based on number of orders received) is assigned.
  • Let’s say that we have a very fast kitchen and the order is ready as soon as we receive it. Check the checkbox next to the "In Process" order and click "Order Ready" button. The host sends the order status to all the devices on the network and updates the status in the grid. See below regarding INotifyPropertyChanged.
  • The Windows Phone 7 devices receive the order status on all devices. Alternatively we could have filtered it to just send to the device submitting the order.

Here is a screenshot after an order is complete:

clip_image006

Understanding the code

Here are the key pieces to understand about the code.

Joining the group: The devices join the group using the following key components:

/// <summary>
/// All communication takes place using a UdpAnySourceMulticastChannel.
/// A UdpAnySourceMulticastChannel is a wrapper we create around the UdpAnySourceMulticastClient.
/// </summary>
/// <value>The channel.</value>
private UdpAnySourceMulticastChannel Channel { get; set; }

/// <summary>
/// The IP address of the multicast group.
/// </summary>
/// <remarks>
/// A multicast group is defined by a multicast group address, which is an IP address
/// that must be in the range from 224.0.0.0 to 239.255.255.255. Multicast addresses in
/// the range from 224.0.0.0 to 224.0.0.255 inclusive are well-known reserved multicast
/// addresses. For example, 224.0.0.0 is the Base address, 224.0.0.1 is the multicast group
/// address that represents all systems on the same physical network, and 224.0.0.2 represents
/// all routers on the same physical network.The Internet Assigned Numbers Authority (IANA) is
/// responsible for this list of reserved addresses. For more information on the reserved
/// address assignments, please see the IANA website.
/// http://go.microsoft.com/fwlink/?LinkId=221630
/// </remarks>
private const string GROUP_ADDRESS = "224.0.1.11";

/// <summary>
/// This defines the port number through which all communication with the multicast group will take place.
/// </summary>
/// <remarks>
/// The value in this example is arbitrary and you are free to choose your own.
/// </remarks>
private const int GROUP_PORT = 54329;

The following command is issued to join the group:

//Send command to join the multi cast group
App.Order.Join(serverName);

And finally the join method opens the channel for communication.

/// <summary>
/// Join the multicast group.
/// </summary>
/// <param name="serverName">The server name I want to join as.</param>
/// <remarks>The server name is not needed for multicast communication. it is
/// used in this example to identify each member of the multicast group with
/// a friendly name. </remarks>
public void Join(string serverName)
{
    if (IsJoined)
       {
           return;
    }

       // Store my player name
       _serverName = serverName;

       //Open the connection
       this.Channel.Open();
}

We subscribe to the following events for processing:

/// <summary>
/// Register for events on the multicast channel.
/// </summary>
private void RegisterEvents()
{
    // Register for events from the multicast channel
       this.Channel.Joined += new EventHandler(Channel_Joined);
       this.Channel.BeforeClose += new EventHandler(Channel_BeforeClose);
       this.Channel.PacketReceived += new EventHandler<UdpPacketReceivedEventArgs>(Channel_PacketReceived);
}

Of particular note is the “PacketReceived” event. We process all commands received (Device and Host) in this event handler. Simply put, we parse the incoming message and identify the command being sent. Based on the command and the number of arguments we further identify the action to take.

Sending the order: The following command is issued when the user clicks the Order button:

App.Order.SendOrder(txtOrder.Text, TableSlider.Value.ToString(), spiceSlider.Value.ToString());

/// <summary>
/// Send the order
/// </summary>
/// <param name="Order"></param>
/// <param name="tableNumber"></param>
/// <param name="spiceLevel"></param>
public void SendOrder(string Order,string tableNumber, string spiceLevel)
{
    if (this.Channel != null)
       {
           //Send order to all devices. Only the server will process the send order command. Others will simply ignore it.
                this.Channel.Send(RestaurantCommands.SendOrderFormat, _serverName, Order, tableNumber, spiceLevel);
    }
}

Our “SendOrderFormat” looks like this:

public const string SendOrder = "SO";
public const string SendOrderFormat = SendOrder + CommandDelimeter + "{0}" + CommandDelimeter + "{1}" + CommandDelimeter + "{2}" + CommandDelimeter + "{3}";

Here is the code for the Send method:

/// <summary>
/// Sends the specified format. This is a multicast message that is sent to all members of the multicast group.
/// </summary>
/// <param name="format">The format.</param>
/// <param name="args">The args.</param>
public void Send(string format, params object[] args)
{
    try
    {
        if (this.IsJoined)
        {
            byte[] data = Encoding.UTF8.GetBytes(string.Format(format, args));
            this.Client.BeginSendToGroup(data, 0, data.Length, new AsyncCallback(SendToGroupCallback), null);
        }
    }
    catch (SocketException socketEx)
    {

        // See if we can do something when a SocketException occurs.
        HandleSocketException(socketEx);
    }
    catch (InvalidOperationException)
    {
        Debug.WriteLine("BeginSendToGroup IOE");
    }
}

So, as we can see, based on the format the message is formatted and transmitted.

Receiving the order:

On the host the message is received by the handler defined for the “PacketReceived” event: void Channel_PacketReceived(object sender, UdpPacketReceivedEventArgs e)

We parse the message and identify the command.

string message = e.Message.Trim('\0');
string[] messageParts = message.Split(RestaurantCommands.CommandDelimeter.ToCharArray());

else if (messageParts.Length == 5 && messageParts[0]== RestaurantCommands.SendOrder)
{
    //Status of order received
       OrderReceivedEventArgs args = new OrderReceivedEventArgs();
       args.tableNumber = Convert.ToInt32(messageParts[3]);
       args.spiceLevel = Convert.ToInt32( messageParts[4]);
       args.order = messageParts[2];
       if (DataReceivedFromDevice != null)
       {
           DataReceivedFromDevice(this, args);
    }
}

It’s a very simple communication mechanism. Once we have identified, parsed and created our arguments for the data received method, we raise it.

In our host application we handle the event and add the incoming order to the orders collection:

/// <summary>
/// Handles incoming orders
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Order_DataReceivedFromDevice(object sender, OrderReceivedEventArgs e)
{
    int OrderID = App.OrdersCollection.Count +1;
       Orders objOrders = new Orders(OrderID, e.tableNumber, e.spiceLevel, e.order);
       App.OrdersCollection.Add(objOrders);
}

Known Issues

· Once in a while you will receive an error when you stop debugging:

· File or assembly name ‘System.Net.debug.resources, Version=2.0.5.0, Culture=en-US, PublicKeyToken=7cec85d7bea7798e’, or one of its dependencies, was not found.

· This is a known issue as indicated here http://forums.create.msdn.com/forums/p/89666/537141.aspx . Sometimes after this error is raised, you have to close visual studio and re-launch it.

INotifyPropertyChanged

This interface has to be implemented on the objects we use to bind to the datagrids. Even if the object collections are declared like shown below, the user interface does not update unless the properties in the object itself raise the property changed event.

public static ObservableCollection<DeviceInfo> Devices = new ObservableCollection<DeviceInfo>();

Sending Order Status: Similar to the above, a similar mechanism is implemented to send the order status:

/// <summary>
/// Sends the order status
/// </summary>
/// <param name="OrderID"></param>
/// <param name="status"></param>
public void SendOrderStatus(int OrderID, string status)
{
    if (this.Channel != null)
{
           //Send order to all devices. Only the server will process the send order command. Others will simply ignore it.
this.Channel.Send(RestaurantCommands.ReceiveOrderFormat, _serverName, OrderID, status);
}
}

public const string ReceiveOrder = "RO";
        
public const string ReceiveOrderFormat = ReceiveOrder + CommandDelimeter + "{0}" + CommandDelimeter + "{1}" + CommandDelimeter + "{2}";

else if (messageParts.Length == 4 && messageParts[0] == RestaurantCommands.ReceiveOrder)
{
    //Status of order received
       OrderStatusReceivedEventArgs args = new OrderStatusReceivedEventArgs();
       args.orderId = Convert.ToInt32(messageParts[2]);
       args.orderStatus = messageParts[3];
       if (DataReceivedFromDevice != null)
       {
        DataReceivedFromDevice(this, args);
    }
}

/// <summary>
/// Shows a message box with the order status
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void Order_DataReceivedFromDevice(object sender, OrderStatusReceivedEventArgs e)
{
    DiagnosticsHelper.SafeShow("Order Status of '" +e.orderStatus + "' Received For Order:" + e.orderId.ToString());
}

Summary

So, using the helpers provided it is fairly simple to implement an application using sockets. This application can be turned into a comprehensive restaurant application by simply extending some features as noted and many others:

  • Add the ability to select from a menu
  • Add the ability to see the pending orders on the devices
  • Add the ability to sign in

The basic steps to building a socket application are:

  • Decide on the type of socket application: Multicast (UDP) or UniCast (TCP).
  • Decide on the commands.
  • Communicate.
  • Process.

This should give you a good overview of sockets support in windows phone 7. Check out the code examples provided at http://msdn.microsoft.com/en-us/library/hh202874(v=vs.92).aspx

To download this entire sample Windows Phone application using sockets, click the Download Code button below:

download

Tomorrow, Matt Eland is going to walk you through using App Connect (also known as search extensibility) to get your application in front of users, even if they haven’t installed it on their device.  See you then!

toolsbutton

31 Days of Mango | Day #20: Creating Ringtones

Day20-RingtonesDay19-AddingTiltEffectsDay18-ExpressionBlendSampleDataDay17-WindowsAzureDay16-IsolatedStorageExplorer

This article is Day #20 in a series called 31 Days of Mango, and was written by guest author Jerrel Blankenship.  (Yes, I realize the remarkable similarities between our names.)  Jerrel can be reached on Twitter at @thejerrel, and you can find his book, Pro Agile .NET Development with Scrum on Amazon.

Today, we are going to talk about ringtones. With the Mango update of Windows Phone, you as a developer have the ability to write applications that can save a user customized ringtone to their device, for later use. This ability is another way to give the user a chance to have a more customized experience on their phone.

Criteria for audio file

Before you can save a ringtone to the phone, there are some stipulations on the audio file that you need to know.

The audio file must meet the following criteria:

  • It can only be in the WMA or MP3 format
  • It can be no larger than 1MB
  • It be unlocked (DRM free)
  • It can be no longer than approximately 40 seconds

SaveRingtoneTask Chooser method

To save a ringtone from your application to the system, you need to use the Chooser API. The Chooser is an API that allows the caller the ability to launch system applications from their own application. Examples of this include the ability to launch the Contacts app to get information about a person, the Bing Maps application to find directions to a location, and launch the Ringtones application. The Ringtones application is an application that allows you to save a ringtone audio file to the ringtones list in the system. The Chooser task you need to call to launch the Ringtones application is called SaveRingtoneTask.

Creating a custom ringtone application

To better understand this and how to use this task, lets build our own ringtone application that takes an audio file from the app and saves it to the system ringtone list.

image_thumb1

To call the SaveRingtoneTask Chooser, you simply need to instantiate a new instance of this chooser and define a delegate that will be ran once the user is complete with the Ringtones application. The sample below displays the application pictured above. To reference this Chooser task, you need to make sure you included the Microsoft.Phone.Task using.

using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Tasks;

namespace CustomRingtonesExample
{
    public partial class MainPage : PhoneApplicationPage
    {
        private readonly SaveRingtoneTask _customRingtone;
        
        public MainPage()
        {
            InitializeComponent();
            _customRingtone = new SaveRingtoneTask();
            _customRingtone.Completed += customRingtone_Completed;
        }

        private void customRingtone_Completed(object sender, TaskEventArgs e)
        {
            MessageBox.Show(@"You are back from the Ringtones application. Reference e.TaskResult, in your code, 
            if you want to see if the save was successful.");
        }

        private void SaveButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            _customRingtone.Source = new Uri("appdata:/Audio/ExampleRingtone.wma");
            _customRingtone.DisplayName = "Example Custom Ringtone";
            _customRingtone.Show();
        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Things to take note of:

  • You need to define a Completed event handler that will run once the user has completed the task. This method is a great place to check to see what the user did in the task and act accordingly.
  • To call the application, you just need to call the Show() method on the chooser.
  • You can access audio files from data that is part of the application (appdata:) as well as from isolated storage (isostore:).

Summary

To wrap up things for today, custom ringtones give the user a chance to have a more personalized experience with their new Window Phone. By calling the SaveRingtonTask, you can provide a gateway for the user to be able to add this level of customization to their phone.

Have fun coding!

To download a working version of the Windows Phone application covered in this article, click the Download Code button below.

download

Tomorrow, Parag Joshi will be covering a new technology available to Windows Phone developers that has been in very high demand: sockets.  See you then!

toolsbutton

31 Days of Mango | Day #19: Tilt Effects

Day19-AddingTiltEffectsDay18-ExpressionBlendSampleDataDay17-WindowsAzureDay16-IsolatedStorageExplorerDay15-ProgressBar

This article is Day #19 in a series called 31 Days of Mango, and was written by guest author Doug Mair. Doug can be reached on Twitter at @doug_mair or at doug.mair@gmail.com.

Applications that look and behave like the native Windows Phone applications will be more attractive to users than applications that don’t behave like the native applications. So, your applications should try to incorporate as much native behavior as possible. A control behavior that is common in many of the native applications is the TiltEffect behavior. Look at the Phone application, which is used for making telephone calls. When you start the Phone app you see a list of users you have called.

Now pay attention as you select an item in the list. When you select that item, you can see a slight tilt to the item that you select. As you release the item, it returns back to its original position. This slight tilt animation gives you a reassurance that the Phone application has received your input. It is a subtle change, but it will increase your users delight.

This article shows you how to add the TiltEffect behavior to controls in your Silver Light applications. A sample application is created which shows the TiltEffect behavior in action and how to turn the TiltEffect behavior on and off at runtime.

Setup for using the TiltEffect Behavior

The TiltEffect behavior is not included in the controls out of the box. We have to get it from a sample that Microsoft released so that third party developers could add this behavior to their applications. The behavior that we are going to use is in a C# file called TiltEffect.cs in the Control Tilt Effect Sample on MSDN.

First of all, download that sample and extract the files to a folder on your computer. The TiltEffect.cs file is in the ControlTiltEffect subdirectory with all of the other source code for the sample. Note the location of the file so that you can add it to your project.

To add it to your Silver Light project, you need to ….

1. Open your project in Visual Studio and right-mouse click on your project.

2. Select the Add menu option, and then select the Existing Item… menu option.

clip_image002_thumb2

3. In the Add Existing Item dialog navigate to and select the TiltEffect.cs file that you downloaded earlier.

4. This will make a copy of the file in your project source directory and will add it to your project.

Namespace

Open the TiltEffect.cs file. Notice that the namespace for this file is ControlTiltEffect. You can either change it to be the same namespace as your project, or leave it as is. For our examples, we will leave it as it is in ControlTiltEffect.

When you want to use this TiltEffect in your application you need to add its namespace to files that use it. To add the namespace to the pages that you want to use the TiltEffect behavior on you controls, add these lines to the top of your XAML file:

mlns:local="clr-namespace:ControlTiltEffect"

local:TiltEffect.IsTiltEnabled="True"

This will create a new alias called local for the ControlTiltEffect namespace. This allows the classes in that namespace to be available on this page.

The second line enables the TiltEffect. With these two lines added, all Buttons and List Boxes on this page will now have the TiltEffect behavior. As you will see later, we can turn on and off the TiltEffect for specific controls on the page.

Now that we know how to add the TiltEffect behavior to our project and XAML pages, lets look at an example of how we would use it an application.

Sample Application

This sample app has many controls which will demonstrate how the TiltEffect behavior works. Most of the buttons and list box items on this page will tilt when you press on them. With TiltEffect.IsTiltEnabled="True" that is the default behavior for the page.

Suppressing TiltEffect on single control: SuppressTilt Property

Suppose that we have a certain button on our page that we don’t want to tilt. We can enable and suppress the TiltEffect for each control or list box item separately. In our sample, the second button will not tilt, this is because the Suppressed property has been set to stop it from tilting. Here’s the XAML code for the second button.

<Button local:TiltEffect.SuppressTilt="True" Content="Tilt Suppressed"

Height="82" HorizontalAlignment="Left" Margin="229,52,0,0"

Name="button2" VerticalAlignment="Top" Width="221" />

Notice that it has the local:TiltEffect.SuppressTilt="True". This suppresses all Tilt effects for this control. The second list box item also has this property set, so it will not tilt either. All of the other controls on this page don’t include this property, so they will tilt.

Stopping TiltEffect for Entire Page: IsTiltEnabled Property

It is also possible to stop the TiltEffect for an entire page. This might be useful for showing a “retro” mode for your application. At the bottom of the page, there is a button labeled “Stop Tilts”. When this button is clicked, all TiltEffects on this page will be stopped. If you press it again, the TiltEffects will be re-enabled.

The button3_Click event handler does this work. The C# code behind is where this takes place. In order to use the TiltEffects in the C# code behind, we add the using ControlTiltEffect; statement.

Then in the button3_Click handler, we get the current IsTiltEnabled property for the entire page. To do this we use the method GetIsTiltEnabled to read the dependency property for the entire page that was given to it by the TiltEffect class. Note the the this object inside the parentheses represents the entire page. This value is saved in the tiltEnabled variable.

Then we set the content for the ToggleTilting button based on the IsTiltEnabled property.

Lastly, we change the IsTiltEnabled property for the entire page, to be the opposite of what it used to be. This time we are modifying the dependency property with the SetIsTiltEnabled method.

At this point, none of the buttons or list box items will tilt. Try it and see. Then press the ToggleTilting button again to let the buttons tilt again.

using Microsoft.Phone.Controls;

using ControlTiltEffect;

namespace Day19_TiltEffects

{

public partial class MainPage : PhoneApplicationPage

{

// Constructor

public MainPage()

{

InitializeComponent();

}

private void button3_Click(object sender, RoutedEventArgs e)

{

bool tiltEnabled = TiltEffect.GetIsTiltEnabled(this);

ToggleTilting.Content = (tiltEnabled) ? "Start Tilts" : "Stop Tilts";

TiltEffect.SetIsTiltEnabled(this, !tiltEnabled);

}

}

}

Complete XAML Source Code

<phone:PhoneApplicationPage

x:Class="Day19_TiltEffects.MainPage"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;

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&quot;

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;

mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"

FontFamily="{StaticResource PhoneFontFamilyNormal}"

FontSize="{StaticResource PhoneFontSizeNormal}"

Foreground="{StaticResource PhoneForegroundBrush}"

SupportedOrientations="Portrait" Orientation="Portrait"

xmlns:local="clr-namespace:ControlTiltEffect"

local:TiltEffect.IsTiltEnabled="True"

shell:SystemTray.IsVisible="True">

<!–LayoutRoot is the root grid where all page content is placed–>

<Grid x:Name="LayoutRoot" Background="Transparent">

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<!–TitlePanel contains the name of the application and page title–>

<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">

<TextBlock x:Name="ApplicationTitle" Text="Day 19"

Style="{StaticResource PhoneTextNormalStyle}"/>

<TextBlock x:Name="PageTitle" Text="Tilt Effects" Margin="9,-7,0,0"

Style="{StaticResource PhoneTextTitle1Style}" Height="75"

FontSize="56" />

</StackPanel>

<!–ContentPanel – place additional content here–>

<Grid x:Name="ContentPanel" Margin="12,118,12,0" Grid.RowSpan="2">

<TextBlock Height="48" HorizontalAlignment="Left" Margin="20,6,0,0"

Name="textBlock1" Text="Buttons" VerticalAlignment="Top"

Width="402" FontSize="32" FontWeight="Bold" />

<Button Content="Tilts" Height="82" HorizontalAlignment="Left"

Margin="0,52,0,0" Name="button1" VerticalAlignment="Top"

Width="202" />

<Button local:TiltEffect.SuppressTilt="True" Content="Tilt Suppressed"

Height="82" HorizontalAlignment="Left" Margin="229,52,0,0"

Name="button2" VerticalAlignment="Top" Width="221" />

<CheckBox Content="CheckBox" Height="72" HorizontalAlignment="Left"

Margin="229,140,0,0" Name="checkBox1" VerticalAlignment="Top" />

<RadioButton Content="RadioButton" Height="72" HorizontalAlignment="Left"

Margin="9,140,0,0" Name="radioButton1" VerticalAlignment="Top" />

<HyperlinkButton Content="HyperlinkButton" Height="30"

HorizontalAlignment="Left" Margin="20,218,0,0"

Name="hyperlinkButton1" VerticalAlignment="Top" Width="200" />

<TextBlock FontSize="32" FontWeight="Bold" Height="48"

HorizontalAlignment="Left" Margin="20,282,0,0" Name="textBlock2"

Text="ListBox" VerticalAlignment="Top" Width="402" />

<ListBox Height="100" HorizontalAlignment="Left" Margin="24,314,0,0"

Name="listBox1" VerticalAlignment="Top" Width="438" Grid.Row="1">

<ListBoxItem Content="Tilts 1" />

<ListBoxItem local:TiltEffect.SuppressTilt="True"

Content="Tilt Suppressed 2" />

<ListBoxItem Content="Tilts 3" />

</ListBox>

<Button Name="ToggleTilting" Content="Stop Tilts" Height="82"

HorizontalAlignment="Left" Margin="14,495,0,0"

VerticalAlignment="Top" Width="438" Click="button3_Click" />

</Grid>

</Grid>

</phone:PhoneApplicationPage>

Summary

Adding Tilt Effects to your controls add a subtle effect that lets your user know their input was received. It is a little more work to add behaviors like this to your applications, but it will pay off with greater user appeal. You have seen how to add the tilt behavior to you app, how to enable it for entire pages, how to disable it for single control and how to disable it for the entire page. Attention to seemingly small details like this will help your application stand out.

BTW, if you are curious, I suggest that you take a look inside the TiltEffect.cs file. It is an excellent example of how to use storyboards and touch manipulations to build effects from the bare bones up. Taking some time to understand how behaviors like this are built will increase your knowledge and confidence with the Windows Phone development. This is a versatile control that you can adapt in other ways if needed.

To download a complete working Windows Phone project that demonstrates Tilt Effects, click the Download Code button below:

download

Tomorrow, we are going to look at creating custom ringtones for your users, and how Windows Phone now supports this awesome new feature.  See you then!

toolsbutton