Home About Me Follow Me on Twitter @mikefrancis Subscribe WP7 Resources WM Resources
# Tuesday, September 27, 2011

The following is a summary of some of the performance measurement tools available from Microsoft for Windows Phone applications.

Marketplace Test Kit – Automated tests for peak memory usage, launch time, app closure, and back button.

These tests are part of the Windows Phone 7.1 SDK. To launch the tools, right click on your project in Visual Studio and select ‘Open Marketplace Test Kit’.

Test Name

Test Description

Launch time

Validation of application launch time.

Peak memory consumption

Validation of application peak memory consumption

Application closure

Validation of all exceptions being handled and application not closing unexpectedly.

Use of Back Button

Validation of proper behavior when pressing the Back button.

Frame Rate Counters for Drawing Performance

To enable:

Application.Current.Host.Settings.EnableFrameRateCounter = true;
Microsoft.Phone.Shell.SystemTray.IsVisible = false; // System Tray not visible 
image

Render Thread FPS: The number of frames per second that the independent simple animations and rendering thread is using. Keeping around 60 will provide a great experience, while a number of 30 fps will begin to show a poor experience to the end user.

Under 30 fps this counter will turn red in post-beta builds.

User Interface Thread FPS: The number of fps that the primary user interface thread is experiencing. Property change notifications, data binding, primary managed code execution, and animations not handled on the render thread use this threads’ resources.

Turns red when the count is at or below 15 fps.

Texture Memory Usage: A specialized memory counter indicating the video memory used for storing application textures.

Surface Counter: A count of the number of surfaces that are passed to the graphics chip.

Intermediate Texture Count: The number of intermediate textures created for compositing.

Screen Fill Rate: A metric representing the number of complete phone screens being painted each and every frame.

Memory APIs for measuring / logging memory usage

long applicationCurrentMemoryUsage = 
     (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationCurrentMemoryUsage");
long applicationPeakMemoryUsage = 
     (long)Microsoft.Phone.Info.DeviceExtendedProperties.GetValue("ApplicationPeakMemoryUsage"); 
Thanks,

Mike

posted on Tuesday, September 27, 2011 9:35:54 PM UTC  #    Comments [1] Trackback
# Monday, July 25, 2011

apphub

 

Todd Brix gives a summary here of the new features included in the App Hub Update that went live on July 18th. In this post I’ll review a couple of the new features and tips for using them.

App Name now determined by XAP, not entry in App Hub.

Previously you provided the application name in the description step (step 2) See screenshot below. You needed to specify this for each language your application supported. (See below.)

Pre-July 2011 App Hub Update - app name provided by developer for each language app supported.

Now with the App Hub update, the application name is derived from the Title attribute of the App element in WMAppManifest.xml:

<App xmlns="" ProductID="{xxx5d2d6-ebb1-4e5b-bd12-7e1371696e80}" Title="People and Places" 
       RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal" 
       Author="Mike Francis" Description="" Publisher="Mike Francis">

This is great improvement since now the application title is maintained in one place: your application. See this blog post for information on localizing the application title.  App Hub will automatically retrieve the appropriate localized application title for each supported language. See here for a sample project with this implemented. Try creating a test submission (you can delete it later) and upload the resulting XAP file from the sample. Note how App Hub is creating a language version for each language supported. Also note how the localized application name is automatically populated.

image

Default Language now must be specified in Project Settings

As stated in this forum post, the App Hub now requires a default language specified in your application. This is the ‘Neutral Language’ assembly setting in Project settings.

  1. Right Click on your project in Solution Explorer
  2. Application | Assembly Information. . .
  3. Neutral Language
  4. Pick a specific default language. For example for English:

image 

App artwork can now be specified in one click!

In the ‘Describe’ section (step 2) of your application submission, you provide the screenshots and icons that are used by the PC and Phone versions of Marketplace. Another nice AppHub feature is the ability to upload all of the artwork at once. You can do this as long as you have the art work in the same directory. For my application, I have created a directory <Project Name>\Images\Marketplace and placed my icons and screenshots there. Then when submitting my app, in the ‘Artwork’ section of step 2, I click ‘Browse”, and multi-select all of the artwork in this folder. App Hub intelligently associates the correct size icon with the corresponding App Hub icon slot. See video below.

App Hub: One click application art upload

Tip: This feature reads the screenshot images in alphabetical order, so if you care about the order of your screenshots, rename them so that the filenames are in alpha-order. This way when the tool reads in your screenshots, they will be in the order you expect. For example, (1ScreenShot.png, 1ScreenShot.png, etc.)

screenshots in alpha order

Thanks,

Mike

posted on Monday, July 25, 2011 8:02:15 AM UTC  #    Comments [0] Trackback
# Saturday, July 02, 2011

image

The Coding4Fun library (http://coding4fun.codeplex.com) for Windows Phone 7 includes many super useful classes that will save you time when writing Windows Phone 7 applications. My favorite is their implementation of very the professional looking and easily extensible user prompts.

While a good assortment of prompts, utilities and other controls have been implemented in coding4fun, what is missing is a login prompt. In this post I’ll review how I’ve used Coding4Fun to create a login prompt.

Can’t I just use a login page?

Many developers have struggled with the Microsoft enforced application navigation flow that mandates:
1) Pressing the Back button must return the application to the previous page or return to any previous page within the back stack.
2) Pressing the Back button from the first screen of an application must close the application.

These rules are difficult to reconcile with an application that has a login prompt on the first page. A couple of problems with this:
1) After the user has successfully logged in, and they have navigated away from the login page, it is confusing if pressing BACK returns them to the Login screen. The expectation is that once they have logged in they should not see the login screen again.
2) Even if you structure the program to navigate to the Login page automatically from the main page if the user has not yet logged in, this gets rid of the ‘BACK navigates to the Login screen’ problem, but it violates the first rule above where BACK on the first screen should exit the app.

See Peter Torr’s article, Introducing the concept of “Places”, for a way to think of ‘places’ and ‘transient UI’. In Peter's article, he recommends one way to handle the login scenario is with the use of a popup. Enter Coding4Fun.

How It Works

The Coding4Fun’s MessagePrompt class, includes a Body property that you can use to add code on the fly. For example:

messagePrompt.Body = new TextBlock { Text = "Hello World!", Foreground = new SolidColorBrush(Colors.Green),

FontSize = 30.0}

I extended this idea to include, a user control ‘LoginUserControl’ which contains the XAML layout and Username and Password members which are databound to the user control.

In the code below I instantiate the LoginUserControl control, add it to the Body member of an instance of MessagePrompt, display the prompt, and process the user results.

private void Button_Click(object sender, RoutedEventArgs e)
{
    var luc = new LoginUserControl(); // Customer user control with Login UI
    MessagePrompt messagePrompt = new MessagePrompt(); // Coding4Fun extensible MessagePrompt
    messagePrompt.IsCancelVisible = true; // Show cancel button
            
    messagePrompt.Body = luc; // Add user control as body of MessagePrompt
    messagePrompt.Completed += (str, res)=> // Handler for MessagePrompt user action
    {
 
       if (res.PopUpResult == PopUpResult.Cancelled)
        {
            luc.Username = luc.Password = "";
            MessageBox.Show("Login Cancelled");
        }
        else
        {
            MessageBox.Show(string.Format("Username: {0}, Password: {1}", luc.Username, luc.Password));
        }
    };
            
    messagePrompt.Show(); 
}

You can download the sample code here.

Mike

posted on Saturday, July 02, 2011 7:32:02 AM UTC  #    Comments [0] Trackback
# Thursday, May 26, 2011

A couple developers I have been working with have had a problem with their application crashing during certification testing, or their app not working as expected after being published. This problem was difficult to debug since the app worked fine for the developer, but would crash out of the gate during testing. After some investigation, we found that the developer was relying on the Product ID to be a known value.

The Product ID is a GUID used to identify your application in the Windows Phone installed application list. This value stays the same across application updates. The Product ID is not controlled by the developer, but is assigned during the ingestion process. That is, the value created by Visual Studio and stored in WMAppManifest.xml, is not the value that will be used when the application is published.

If you are relying on the Product ID to be a certain value – it won’t be what you expect, when your application is published.

<App xmlns="" 
      ProductID="{eb186f6f-78ab-49d2-937d-daa5d0cb7889}" 
      Title="BestAppEver" RuntimeType="Silverlight" Version="1.0.0.0" Genre="apps.normal"
      Author="BestAppEver author" Description="Sample description" Publisher="Cookie1">

Here are a couple of workarounds to consider:

  1. Instead of using the Product ID, use a private scheme to store the unique value your app needs.
  2. If your really need to use the Product ID, you can leverage the way App Hub works. That is, the Product ID is assigned early on in the submission process. Specifically, in Step 1 when you upload your app. You can upload a preliminary version of your app and not submit it for testing. You can then use this Product ID in your code. When your application is ready for submission, you can re-upload your app, overwriting the preliminary version with the final version. The Product ID will not change. See below for sample code on how to read the Product ID at run-time.

To see the Product ID as assigned by Product ID, in your “my apps” list on the dashboard, click on the name of your submission.

clip_image002

Here, you can see the Product ID and the Deep Link. This will not change for this submission.

clip_image004

Code to read the Product ID at run time:

public static string GetProductId() 
{
    System.Xml.Linq.XElement xml = System.Xml.Linq.XElement.Load("WMAppManifest.xml");
    var appElement = (from manifest in xml.Descendants("App") select manifest).SingleOrDefault();
    if (appElement != null) { 
        return appElement.Attribute("ProductID").Value; 
    } 
    return string.Empty; 
}
Mike
posted on Thursday, May 26, 2011 1:21:03 AM UTC  #    Comments [0] Trackback
# Friday, May 13, 2011

To submit your app to Marketplace for distribution, you will need an App Hub Account. Open one at: http://create.msdn.com

Opening an account is also necessary to developer unlock your Windows Phone 7 hardware.

Tip: Make sure you use an international credit card if opening an account outside of the US.
Tip: If you will use this account for a company, do not use a personal Windows Live ID when creating the account. You don’t want to mix your personal account details with your company’s and after you create the account, you can’t change the Windows Live ID.

For a guide of the Windows Phone 7 registration process, see here.

For a guide of the Windows Phone 7 Marketplace application submission process, see here.

To help teams track their progress in meeting the Windows Phone 7 certification requirements, I’ve created the following guide. I have used this myself when reviewing partners applications prior to submitting to Marketplace. Please see the instructions on the first tab.

image

Instructions

image

Sample Page

Thanks,

Mike

This work is licensed under a Creative Commons license.
posted on Friday, May 13, 2011 5:37:46 PM UTC  #    Comments [0] Trackback
# Friday, July 16, 2010

There are a couple of ways to go about detecting Tap and Hold in Windows Phone 7. This method uses the XNA Touch Gesture recognizer (Microsoft.Xna.Framework.Input.Touch) in a Silverlight application.  The touch gesture recognizer can tell the difference between tap, double-tap,  and hold gestures. Additionally, using the XNA gesture recognizer you don’t need to worry about mistaking a pan/drag for a hold: if you move your finger too much, a tap or hold won’t be recognized. Other solutions involve inferring these events through the use of a timer.  A common application of this is to implement a context menu in your Windows Phone 7 application.

This method handles the ManipulationStarted event to detect the initial tap. In this event, you tell the gesture recognizer which gestures you want to monitor. In this case, tap, double-tap, and hold.  (This is also done in the constructor of the page, to initialize the recognizer.)

Next a 500 ms timer is started. The timer is used to detect when enough ‘hold time’ has elapsed. When the ‘hold time’ threshold is met, the gesture is detected, the gesture recognizer is reset, and the timer is stopped. This is where you would invoke the context menu. (Not implemented here.) A timer is only necessary here for the implementation of a context-menu. You could detect the gesture in the ManipulationCompleted event handler, which fires when the user releases their finger from the screen.

  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.     TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold | GestureType.DoubleTap;
  5. }
  6.  
  7. System.Windows.Threading.DispatcherTimer dt;
  8. public void StartHoldTimer()
  9. {
  10.     dt = new System.Windows.Threading.DispatcherTimer();
  11.     dt.Interval = new TimeSpan(0, 0, 0, 0, 500);// 500 Milliseconds
  12.     dt.Tick += new EventHandler(dt_Tick);
  13.     dt.Start();
  14. }
  15.  
  16. int cnt = 0;
  17. void dt_Tick(object sender, EventArgs e)
  18. {
  19.     if (cnt == 3) // 500 ms * 4 == 2 seconds
  20.     {
  21.         cnt = 0;
  22.         GetGesture();
  23.         // disable all events
  24.         TouchPanel.EnabledGestures = GestureType.None;
  25.         // stop the hold timer
  26.         StopHoldTimer();
  27.     }
  28.     cnt++;
  29. }
  30.  
  31. void StopHoldTimer()
  32. {
  33.     dt.Stop();
  34.     cnt = 0;
  35. }
  36.  
  37. private void GetGesture()
  38. {
  39.     if (TouchPanel.IsGestureAvailable)
  40.     {
  41.         GestureSample gs = TouchPanel.ReadGesture();
  42.         if (gs.GestureType == GestureType.Hold)
  43.         {
  44.             string gestureString = string.Format("{0}: {1}", gs.GestureType, gs.Position);
  45.             // Tap and Hold detected, report position
  46.             Debug.WriteLine(gestureString);
  47.         }
  48.     }
  49. }
  50.  
  51. private void PhoneApplicationPage_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
  52. {
  53.     // specify what events the XNA gesture recognizer will look out for
  54.     TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Hold | GestureType.DoubleTap;
  55.     // start the hold timer
  56.     StartHoldTimer();
  57. }
  58.  
  59. private void PhoneApplicationPage_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
  60. {
  61.     // disable all events
  62.     TouchPanel.EnabledGestures = GestureType.None;
  63.     // stop the hold timer
  64.     StopHoldTimer();
  65. }

Enjoy!

Mike

This work is licensed under a Creative Commons license.
posted on Friday, July 16, 2010 3:23:45 PM UTC  #    Comments [0] Trackback
# Friday, June 25, 2010

This sample code uses the IsolatedStorageFile class to create a few test directories and populates them with files.  Then it recursively enumerates the files and directories, displaying the output in the debug window.

  1. public void EnumerateIsolatedStorageFiles()
  2. {
  3.     try
  4.     {
  5.         // Get an isolated store for this applicaiton and put it into an
  6.         // IsolatedStorageFile object.
  7.  
  8.         using (IsolatedStorageFile isoStore =
  9.             IsolatedStorageFile.GetUserStoreForApplication())
  10.         {
  11.             // Create sub directories and create files
  12.             // in them to test enumeration
  13.             isoStore.CreateDirectory("A");
  14.             IsolatedStorageFileStream streamA =
  15.                 new IsolatedStorageFileStream(@"A\TestFileA.Txt", FileMode.Create, isoStore);
  16.  
  17.             isoStore.CreateDirectory("B");
  18.             IsolatedStorageFileStream streamB =
  19.                 new IsolatedStorageFileStream(@"B\TestFileB.Txt", FileMode.Create, isoStore);
  20.  
  21.             isoStore.CreateDirectory("C");
  22.             IsolatedStorageFileStream streamC =
  23.                 new IsolatedStorageFileStream(@"C\TestFileC.Txt", FileMode.Create, isoStore);
  24.  
  25.             isoStore.CreateDirectory(@"C\1");
  26.             IsolatedStorageFileStream streamC1 =
  27.                 new IsolatedStorageFileStream(@"C\1\TestFileC1.Txt", FileMode.Create, isoStore);
  28.  
  29.             isoStore.CreateDirectory(@"D\1\2\3\4\5");
  30.             IsolatedStorageFileStream streamD =
  31.                 new IsolatedStorageFileStream(@"D\1\2\3\4\5\TestFileD.Txt", FileMode.Create, isoStore);
  32.  
  33.             streamA.Close();
  34.             streamB.Close();
  35.             streamC.Close();
  36.             streamC1.Close();
  37.             streamD.Close();
  38.  
  39.             // There might be a small delay between when the above code
  40.             // executes and when the files are created in the store.
  41.             // Closing and opening the store in this example ensures that
  42.             // the common language runtime has finished creating the files.
  43.         } // using
  44.  
  45.         using (IsolatedStorageFile isoStore =
  46.             IsolatedStorageFile.GetUserStoreForApplication())
  47.         {
  48.             // List files in root
  49.             foreach (string file in isoStore.GetFileNames())
  50.             {
  51.                 Debug.WriteLine(file);
  52.             }
  53.             // Recursively enumerate sub-directories and list contents
  54.             GetFiles(isoStore, @"\");
  55.         } // using
  56.     }
  57.     catch (IsolatedStorageException e)
  58.     {
  59.         Debug.WriteLine(e.Message);
  60.     }
  61. }
  62.  
  63. // Recursively enumerate sub-directories
  64. void GetFiles(IsolatedStorageFile isoStore, string directory)
  65. {
  66.     string[] DirNames;
  67.     if (directory == @"\")
  68.         DirNames = isoStore.GetDirectoryNames();
  69.     else
  70.         DirNames = isoStore.GetDirectoryNames(directory + @"\*");
  71.  
  72.     foreach (string dir in DirNames)
  73.     {
  74.         string mDir =
  75.             directory == @"\" ? directory + dir : directory + @"\" + dir;
  76.         foreach (string file in isoStore.GetFileNames(mDir + @"\*.*"))
  77.         {
  78.             Debug.WriteLine(file);
  79.         }
  80.         GetFiles(isoStore, mDir);
  81.     }
  82. }

 

Enjoy!

Mike

This work is licensed under a Creative Commons license.
posted on Friday, June 25, 2010 2:59:51 AM UTC  #    Comments [0] Trackback