Home About Me Follow Me on Twitter @mikefrancis Subscribe WP7 Resources WM Resources
# 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
# Sunday, May 30, 2010

Bing Mobile 6.1

 

 

One of my favorite Windows Mobile applications has been Bing (the application formerly known as “Live Search”).  This application has saved my bacon on more than one occasion when travelling on business or vacation. The ability to search for vital resources, wherever I am, like the closest Starbucks has been invaluable to me.

While Live Search was great, the UI was a little clunky and was not developed with capacitive screens and the corresponding touch navigation in-mind. Capacitive screens while more sensitive to touch, have a larger minimum hit target size. Actually comparing Live Search to the new Bing is a good example of how an application designed for a resistive screen has been updated to also work with capacitive screens.

 

The usability has greatly improved. For example to starting navigating to the nearest Starbucks, you:

 

  • From the Bing home page, Tap ‘Speak’ and say ‘Starbucks’

Bing for mobile, like on the desktop, daily updates the cool photo used on the home page background.

  • Select the ‘Starbucks’ you want to go to

Select the appropriate tab to search the web of do a web local search of your search term.

  • Tap the Car icon for driving directions

Note the detail information here including phone number, address, rating, map thumbnail, etc.

  • Tap on ‘Navigate’ (If you are on foot, select the ‘Walk’ tab for walking directions.)

Single click on 'Navigate' to start with voice directions from your current location

Immediately a route is calculated for you and Silicon Sally is telling you where to go. Yes ‘telling you’, with voice directions! This is a huge improvement over Live Search that had text only turn-by-turn directions. In the Bing settings, you can specify if you want to route via the shortest or fastest route. You can also configure Bing to consider real-time traffic conditions when calculating your route. 

By default, you will see traffic conditions on map

Now featuring ‘auto-rerouting’! Live Search would prompt you will a demoralizing ‘Are you lost? Would you like to reroute from here?’ prompt whenever you deviated from your planned route. Bing for mobile smartly just tells you that it is ‘rerouting’ and updates your driving directions based on your current location.

All the great features of Live Search are still here like quick access to locally playing movies and show times.

You can install Bing for mobile from the Marketplace for Windows Phone here.

More information here.

Enjoy!

Mike

posted on Sunday, May 30, 2010 2:43:04 AM UTC  #    Comments [0] Trackback
# Saturday, May 22, 2010
# Friday, April 30, 2010

Update: I've updated the sample to be independent of the '\Program Files' string. Also, the sample now supports installing onto a Storage Card.

A popular sample for demonstrating how to install application dependencies via embedded CAB files is MultiCAB Install. With this pattern you can distribute dependant cab files via a single container CAB. “Can apps be distributed via Windows Marketplace for Mobile using this?”,you ask. Yes they can.

Installing SQL Server Compact dependencies is a good fit for this pattern. I have updated the sample here customized to distribute the latest SQL Server Compact for Windows Mobile devices.

The sample checks if SQL Server Compact 3.5 is installed (See IsSQLCEUpdateRequired() in mcsetup.cpp) and if not, launches the multicab EXE which installs each dependant cab in sequence. (See the multicab whitepaper included in the sample for an in-depth explanation of how it works.)

How does the sample check to see if v3.5 is installed? It checks the registry for the following entry:

  1. \Software\Microsoft\Microsoft SQL Server Compact Edition\v3.5

This this exists, then installation of the SQLCE cabs is skipped. Note that this registry key only exists if SQLCE has been installed via a CAB file. That is, this registry key does not exist of SQLCE is in ROM. As of this writing, 3.5 (SP1 or SP2) is not distributed in ROM. See here for a list of OS and corresponding SQLCE versions: Description of the various build versions of SQL Server Compact Edition.

The sample does not do version checking on the binaries. Therefore it does not detect if you are upgrading from SQLCE 3.5 SP1 to SP2. The way it is written now, it will not update the binaries to SP2. This sample does address the popular scenario of updating an ‘off the shelf’ device with the latest version of SQL Server Compact.

More SQL Server Compact Links: Mike

This work is licensed under a Creative Commons license.
posted on Friday, April 30, 2010 8:51:03 PM UTC  #    Comments [5] Trackback