Category Archives: code

WebBrowser.Touch

Disabling Touch on a WebBrowser control

If you’re presenting content to the user with a WebBrowser control, but it’s not meant to be interacted with, then you will probably want to disable touch input to prevent the user from scrolling or zooming. Although setting IsEnabled or IsHitTestVisible to False can give you want you want, it’s also likely to mess with the appearance (a grey overlay). So, to work round this, use CSS in the source HTML like so:

<style type="text/css">
    html {
        overflow: hidden; /* Disable scrolling */
        -ms-content-zooming: none; /* Disable zooming */
    }
Markdown Notepad

APP: Markdown Notepad

Now available in the Store for Windows Phone 8 apps, my latest app is a simple notepad app that uses the Markdown format. Ingeniously called Markdown Notepad, this app builds on the Markdown features that were built into Visual Diary and extends it with note backup to the cloud. After a few false starts trying to use SkyDrive (a service which I love!) for the cloud backup feature I found that the SDK didn’t give me what I wanted, so I used Buddy instead. Whilst this meant that the service wasn’t quite as friction free as I’d have liked it to have been because I then had to create the user management (registration, login, forgotten password), the API was simple to use and I’ve been really happy. The Buddy team were really responsive and quick to fix the couple of bugs that I found. I’d be happy to share the service wrapper that I created and even consider turning the user management stuff into a reusable control if anyone is interested.

As always, your ratings and reviews are welcome in the Store, and you can give feedback at http://gapshooter.uservoice.com/

Page01 Page02 Page03 Page04 Page05 Page06

Microsoft Advertising

AdException using Microsoft Advertising SDK

When you’re developing Windows Phone apps using the Microsoft Advertising SDK, you may not see any ads when you were expecting to. This is likely to be accompanied by the following message in the Output window in Visual Studio:

An exception of type 'Microsoft.Advertising.Shared.AdException' occurred in Microsoft.Advertising.Mobile.DLL and wasn't handled before a managed/native boundary.

There’s a couple of things to check here:

  1. Make sure you have ID_CAP_PHONE_DIALER in your capabilities (I have no idea why the Ad SDK needs the capability!).
  2. If you’re running in the emulator and using actual Application and Ad Unit Ids, you won’t see any ads. You should use “test_client” and “Image480_80″ for testing (NOTE: the casing is important).
  3. If all else fails, add an event handler for the ErrorOccurred event on the AdControl to see what’s happening:
var ads = new AdControl;
  {
    "test_client",
    "Image480_80",
    true
  };
  ads.ErrorOccurred += (o, e) =>
  {
    System.Diagnostics.Debug.WriteLine(e);
  };

I’m sure this is fairly well covered elsewhere, so it’s more of a “note-to-self”.

Zune

Detecting Zune Connection for PhotoChooserTask

When you’re using the PhotoChooserTask to get the user to select or take a photo you may have experienced the problem when the user is connected to Zune because this prevents them from accessing their media library. Unfortunately, from a development point of view, the Complete event that fires simply provides Cancel as the Result, which is the same result for when the user simply presses the back button.

I’ve seen a few solutions to this problem; one was a timer based hack, one was a complicated solution regarding checking network interface types, and yet another tried to access the MediaLibrary and trap the resulting exception. I think these are relatively old solutions (taking into account that Windows Phone isn’t much over a year old!) and I flat out refused to use the timing hack, the network interface type solution didn’t work because it relied on reporting Ethernet when connected but I was getting None, and the final solution failed to throw the expected exception!

Fortunately, after some more investigation I stumbled across the solution. Not only does the Complete event give a result of Cancel, but the Error property is an InvalidOperationException, which gave me the following solution:

private void PhotoChooser_Complete(object sender, PhotoResult e)
{
    if ((TaskResult.Cancel == e.TaskResult) &amp;&amp;
        (e.Error is InvalidOperationException))
    {
        // Zune software connected.
        MessageBox.Show(
            "Your phone is connected to the Zune software and cannot select a photo. Close the Zune software or disconnect your phone and try again.",
            "Zune Connected",
            MessageBoxButton.OK);
    }
    else if (TaskResult.OK == e.TaskResult)
    {
        // Carry on as usual.
    }
}

NOTE: I actually use a toast-style notification here instead of a message box, but that’s a whole other post :)

Getting Started with the Windows 8 Consumer Preview

There are plenty of posts around on how to actually install the Windows 8 consumer Preview, so I’m not going to both covering that right now, but there were a couple of really useful resources that I wanted to highlight.

First up is some great design resources for designing the user experience for Metro style apps: http://design.windows.com. This includes:

  • Guidance on how to implement common design patterns in Metro style apps for navigation, commanding and touch interaction.
  • PhotoShop design assets for common controls and layouts.
  • Detailed UX guidelines.
  • Guidance for assessing usability.

The other resource is a collection of approximately 200 sample applications in C#, VB.NET, C++, and JavaScript covering pretty much every topic for the new SDK for Windows 8 Metro-style application development: http://code.msdn.microsoft.com/windowsapps/Windows-8-Modern-Style-App-Samples.

Go forth and enjoy!

Don’t Forget!

Parking Tickets

The current approach for reminders works on the assumption that you are using a “pay-and-display”-style car park where you pay in advance to park for a certain amount of time.

Another option would be to track how long you’ve been parked and calculate what your current parking fee is for the shopping centre-style parking where you pay on exit.

If you’re interested in this second model then it would be great if you could give me your feedback over on UserVoice.

One of the many (500+ apparently) new features in Windows Phone 7.1 (codenamed Mango) is the ability to set reminders from your application. I’ve been working on the Mango-enabled version of Car Finder and thought it would be great if the user could set a reminder for when their parking ticket is due to run out.

Get to the API Already!

Ignoring the user interface aspects for now, actually creating a reminder is fairly simply and involves using the ScheduledActionService class. This class is actually the base for  Alarm, Reminder, PeriodicTask, and ResourceIntensiveTask, so it’s quite an important class, but I’ll cover alarms and background agents another time.

I’ll quickly summarise how you use the API, and then give you my helper class afterwards, so don’t worry about the details for now.

Alerts.DarkCreating a Reminder

Creating a new reminder is as simple as calling the Add method and passing a ScheduledAction instance. The ScheduledAction instance for a reminder is a Reminder and contains the time for the reminder to occur, the title and content of the reminder, the URI to navigate to if the reminder is tapped, and how the reminder occurs (if at all). The Reminder also has a name, which is used to identify it in the ScheduledActionService.

Deleting a Reminder

Deleting a reminder simply involves calling the Remove method and supplying the name of the reminder that you want to remove.

Getting a Reminder

You can get the details of an existing reminder by using the Find method and supplying the name of the reminder that you want to get. Handily, this gives you the full Reminder instance that you set when you created the reminder.

The ReminderManager Class

So, that’s (briefly) how you manage reminders, so here’s my helper class that achieves all of the above.

As with my EnterKeyHandler, this code is available as part of the Windows Phone 7 from the Trenches repository at BitBucket. It will also be available (as the EnterKeyhandler already is) on the WP7 Contrib project.

namespace DerekLakin.Common
{
    using System;
    using Microsoft.Phone.Scheduler;

    /// &lt;summary&gt;
    /// Provides a static helper class for managing reminders.
    /// &lt;/summary&gt;
    public static class ReminderManager
    {
        /// &lt;summary&gt;
        /// Adds a new reminder.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;name&quot;&gt;The name of the reminder.&lt;/param&gt;
        /// &lt;param name=&quot;title&quot;&gt;The title of the notification.&lt;/param&gt;
        /// &lt;param name=&quot;body&quot;&gt;The body of the notification.&lt;/param&gt;
        /// &lt;param name=&quot;beginTime&quot;&gt;The time of the reminder.&lt;/param&gt;
        /// &lt;param name=&quot;navigationUri&quot;&gt;The URI to be passed to the application on launch.&lt;/param&gt;
        /// &lt;param name=&quot;recurrence&quot;&gt;The recurrence of the reminder.&lt;/param&gt;
        /// &lt;returns&gt;The new &lt;see cref=&quot;Reminder&quot;/&gt; instance.&lt;/returns&gt;
        public static Reminder AddReminder(
            string name,
            string title,
            string body,
            DateTime beginTime,
            Uri navigationUri,
            RecurrenceInterval recurrence = RecurrenceInterval.None)
        {
            if (HasReminder(name))
            {
                RemoveReminder(name);
            }

            var reminder = new Reminder(name)
            {
                BeginTime = beginTime,
                Content = body,
                NavigationUri = navigationUri,
                RecurrenceType = recurrence,
                Title = title
            };
            ScheduledActionService.Add(reminder);

            return reminder;
        }

        /// &lt;summary&gt;
        /// Gets the reminder with the specified name.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;name&quot;&gt;The name of the reminder.&lt;/param&gt;
        /// &lt;returns&gt;A &lt;see cref=&quot;Reminder&quot;/&gt; instance if found; otherwise &lt;c&gt;null&lt;/c&gt;.&lt;/returns&gt;
        public static Reminder GetReminder(string name)
        {
            var reminder = ScheduledActionService.Find(name) as Reminder;
            return reminder;
        }

        /// &lt;summary&gt;
        /// Determines whether there is a reminder with the specified name.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;name&quot;&gt;The name of the reminder.&lt;/param&gt;
        /// &lt;returns&gt;
        ///&lt;c&gt;True&lt;/c&gt; if there is a reminder with the specified name; otherwise, &lt;c&gt;false&lt;/c&gt;.
        /// &lt;/returns&gt;
        public static bool HasReminder(string name)
        {
            var reminder = GetReminder(name);
            return reminder != null;
        }

        /// &lt;summary&gt;
        /// Removes the reminder with the specified name.
        /// &lt;/summary&gt;
        /// &lt;param name=&quot;name&quot;&gt;The name of the reminder.&lt;/param&gt;
        public static void RemoveReminder(string name)
        {
            if (HasReminder(name))
            {
                ScheduledActionService.Remove(name);
            }
        }
    }
}

 

Using it in Anger

In Car Finder, I have a method that creates a reminder and it looks (more-or-less) like this:

private void CreateReminder()
{
    // NOTE: The ReminderManager handles removing an existing reminder of the
    //       same name if one exists.
    try
    {
        ReminderManager.AddReminder(
            Constants.ReminderKey,
            this.ReminderTitle,
            this.ReminderBody,
            this.ReminderTime,
            null);
    }
    catch (Exception ex)
    {
        this.IsReminderSet = false;
        MessageBox.Show(
            StringTable.Message_ReminderContent,
            StringTable.Message_ErrorCaption,
            MessageBoxButton.OK);
    }
}

In the constructor for the view model, I do a  check to see if a reminder exists and update the local properties accordingly:

/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref=&quot;MainViewModel&quot;/&gt; class.
/// &lt;/summary&gt;
/// &lt;param name=&quot;locationManager&quot;&gt;The location manager.&lt;/param&gt;
/// &lt;param name=&quot;settings&quot;&gt;The application-wide settings.&lt;/param&gt;
/// &lt;param name=&quot;resourceClient&quot;&gt;The resource client.&lt;/param&gt;
public MainViewModel(
    LocationManager locationManager,
    Settings settings,
    IHandleResources resourceClient)
{
    this._locationManager = locationManager;
    this._resourceClient = resourceClient;
    this._settings = settings;

    // ...

    if (ReminderManager.HasReminder(Constants.ReminderKey))
    {
        var reminder = ReminderManager.GetReminder(Constants.ReminderKey);
        if (reminder.BeginTime &gt; DateTime.Now)
        {
            this._reminderTime = reminder.BeginTime;
            this._isReminderSet = true;
        }
        else
        {
            this._reminderTime = DateTime.Now;
            this._isReminderSet = false;
        }
    }
    else
    {
        this._reminderTime = DateTime.Now;
        this._isReminderSet = false;
    }
}

When the toggle switch to set a reminder is cleared, I remove the reminder like so:

public bool IsReminderSet
{
    get
    {
        return this._isReminderSet;
    }

    set
    {
        if (this.UpdateProperty(&quot;IsReminderSet&quot;, ref this._isReminderSet, value))
        {
            if (this._isReminderSet)
            {
                this.CreateReminder();
            }
            else
            {
                ReminderManager.RemoveReminder(Constants.ReminderKey);
            }
        }
    }
}

That’s pretty much all there is to it. I hope you find it useful.

User-Friendly Input Pages

When it comes to data entry pages on mobile devices the key is to make it as simple as possible for the user. These kind of devices are all about the user experience and while I think we can all agree that data entry is far from sexy, it’s unavoidable. I was recently working on the login screen for an app (which will remain secret for now, but I’ll reveal all when it’s published) and realized as I was creating it that that were two common things that I wanted to do in this scenario:

  1. “Tab” from one input field to the next by pressing the Enter key.
  2. Submit the form contents when I got to the last field.

Submit Buttons

When you are implementing a data entry form of some kind, even if it’s as simple as a login page, you should always make sure that the user can see the submit button. When the SIP is displayed (in any orientation) a lot of the page is obscured, making it hard for your user to find a button on the page. As well as ensuring that the content is contained within a ScrollViewer to enable users to scroll around your content, you should put the submit button in the application bar so that the user can easily tap it, even when the SIP is displayed.

Item 1 enables the user to move from one input field to the next without having to manually tap on the input controls, which can get really annoying for the user, especially when the SIP is displayed. Item 2 is definitely a “nice-to-have” because if the data entry page is designed properly, there’s a submit button on the application bar, which the user can tap without having to dismiss the SIP. However, if the user is already used to pressing the Enter key to “tab” between fields, it just makes their life easier if the final Enter key press actually does a submit.

I’ve seen solutions for this already, which I’ve used in the past, specifically the KeyboardTabHelperBehavior by @pauliom, but it wasn’t quite what I wanted.

“Tabbing” Between Fields

So, I set about creating my own behavior and tackled the issue of the “tabbing” aspect first. The key here is to handle the Enter key press, and then find another TextBox or PasswordBox control to set focus to.

The scaffolding of the behavior looks like this:

public class EnterKeyHandler : Behavior&lt;Control&gt;
{
    protected override void OnAttached()
    {
        base.OnAttached();

        if (null != this.AssociatedObject)
        {
            this.AssociatedObject.KeyDown += this.Control_KeyDown;
        }
    }

    /// &lt;summary&gt;
    /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
    /// &lt;/summary&gt;
    /// &lt;remarks&gt;Override this to unhook functionality from the AssociatedObject.&lt;/remarks&gt;
    protected override void OnDetaching()
    {
        base.OnDetaching();

        if (null != this.AssociatedObject)
        {
            this.AssociatedObject.KeyDown -= this.Control_KeyDown;
        }
    }

    private void Control_KeyDown(object sender, KeyEventArgs args)
    {
        if ((Key.Enter == args.Key) ||
            (0x0A == args.PlatformKeyCode))
        {
            this.FocusNextTextOrPasswordBox();
        }
    }
}

PlatformKeyCode

Handling the value 0x0A for the args.PlatformKeyCode adds support for the Enter key on the host keyboard when running in the emulator.

The work horse for the first part of the behavior is the FocusNextTextOrPasswordBox method, which uses the LinqToVisualTree helper by @ColinEberhardt to find the next TextBox or PasswordBox after the AssociatedObject. If it doesn’t find one, it finds the first TextBox or PasswordBox before itself, i.e. it loops round to the start again. If it finds either a TextBox or PasswordBox, it sets focus to it, which ensures that the SIP remains visible and any changes to InputScope will be taken into account. The method looks like this:

    private void FocusNextTextOrPasswordBox()
    {
        // Find the next TextBox or PasswordBox.
        var target = this.AssociatedObject
            .ElementsAfterSelf()
            .Where((d) =&gt; d is TextBox || d is PasswordBox)
            .FirstOrDefault() as Control;
        if (null == target)
        {
            // Nothing after this one, so try predecessors so that we loop round.
            target = this.AssociatedObject
                .ElementsBeforeSelf()
                .Where((d) =&gt; d is TextBox || d is PasswordBox)
                .FirstOrDefault() as Control;
        }

        if (null != target)
        {
            target.Focus();
        }
    }

Executing a Command

The next stage is to execute my submit command when I get to the end of the input, so I needed an enumeration to identify the different modes of operation and a dependency property to expose it. I called these EnterKeyAction and EnterKeyActionProperty respectively.

The Control_KeyDown method shown above becomes the following:

    private void Control_KeyDown(object sender, KeyEventArgs args)
    {
        if ((Key.Enter == args.Key) ||
            (0x0A == args.PlatformKeyCode))
        {
            if (this.EnterKeyAction == EnterKeyAction.MoveNext)
            {
                this.FocusNextTextOrPasswordBox();
            }
            else
            {
                this.ExecuteAssociatedCommand();
            }
        }
    }

The next thing I needed to do was to enable the developer to specify the command that the behavior should execute. My first attempt was to simply expose an ICommand dependency property to enable binding to the view model, but unfortunately that didn’t work, presumably because the behavior doesn’t have the concept of a data context meaning that there’s nothing for it to bind to. So, I dug out my ninja reflection skills and changed to a CommandStringProperty that is used to find the command to execute, which is where the ExecuteAssociatedCommand method comes in:

    private void ExecuteAssociatedCommand()
    {
        // Locate the named command in the associated objects data context, and then
        // execute that command.
        var commandName = this.CommandString;
        if (!string.IsNullOrEmpty(commandName))
        {
            var context = this.AssociatedObject.DataContext;
            if (null != context)
            {
                var info = (from p in context.GetType().GetProperties()
                            where
                                p.CanRead &amp;&amp;
                                p.Name == commandName &amp;&amp;
                                typeof(ICommand).IsAssignableFrom(p.PropertyType)
                            select p).SingleOrDefault();
                if (null != info)
                {
                    var command = info.GetGetMethod().Invoke(context, new object[0])
                        as ICommand;
                    if (null != command)
                    {
                        command.Execute(null);
                    }
                }
            }
        }
    }

This method finds the data context of the AssociatedObject on the assumption that it’s set to the view model, and then uses reflection to find the properties that have read access, whose name matches the specified CommandString, and that implement the ICommand interface. If it finds a match, it gets the value of the property, and then executes it. Job done!

Because the key scenario here is simple form submission, I’m not expecting there to be any command parameter, and in the absence of a working binding solution, I figured that was two good reasons not to expose it.

EnterKeyHandler in Action

You’ll need to add a reference to the System.Windows.Interactivity.dll assembly from the Expression Blend SDK and include the source code in your project, which you can download from the Windows Phone 7 from the Trenches repository at BitBucket. The EnterKeyHandler behavior is in the Behaviors folder, and the LinqToVisualTree class is in the Extensions folder. Then it’s all about the XAML:

&lt;StackPanel x:Name=&quot;LayoutRoot&quot; Background=&quot;Transparent&quot;&gt;
    &lt;TextBlock Style=&quot;{StaticResource PhoneTextSubtleStyle}&quot;
               Text=&quot;user name or email address&quot; /&gt;
    &lt;TextBox Text=&quot;{Binding EmailAddress, Mode=TwoWay}&quot;&gt;
        &lt;int:Interaction.Behaviors&gt;
            &lt;b:EnterKeyHandler /&gt;
        &lt;/int:Interaction.Behaviors&gt;
    &lt;/TextBox&gt;
    &lt;TextBlock Style=&quot;{StaticResource PhoneTextSubtleStyle}&quot;
               Text=&quot;password&quot; /&gt;
    &lt;PasswordBox Password=&quot;{Binding Password, Mode=TwoWay}&quot;&gt;
        &lt;int:Interaction.Behaviors&gt;
            &lt;b:EnterKeyHandler EnterKeyAction=&quot;ExecuteCommand&quot;
                               CommandString=&quot;SignInCommand&quot; /&gt;
        &lt;/int:Interaction.Behaviors&gt;
    &lt;/PasswordBox&gt;
&lt;/StackPanel&gt;


This XAML has a simple TextBox for the user name and a PasswordBox for the password. The first uses the default behavior of moving to the next input field, and the second uses the ExecuteCommand action to execute the SignInCommand. The data context for the UI is my view model, which exposes the SignInCommand property. I also have an application bar button that is hooked up to the same command.

Creating Copyable Read-Only Text

Ignoring any debates or discussions about when it’s going to arrive if you haven’t got it already, but the recently-released update for Windows Phone 7 (WP7) code-named NoDo (apparently short for No Donuts) brought the much discussed copy and paste feature.

How Does it Work?

The copy and paste feature has been available in the developer tools since December 2010, so we already know that the copy and paste feature works in the following scenarios:

  • TextBox
  • PasswordBox
  • WebBrowser control, but only for TextBox elements on a web page, NOT all text.
  • Internet Explorer(IE), for any text not just TextBox elements.

IE vs. WebBrowser Control

I’m not going to go into why the WebBrowser control only supports this feature for HTML textboxes, but IE supports it for plain text as well (mainly because I don’t know), but if Brandon Watson or Charlie Kindel read this, I’d love to hear an explanation. For now we just have to deal with this fact and move on. Hopefully, in time this feature will be improved upon in a future release.

copyTo copy a word simply tap on that word and it gets highlighted with the copy icon above it. You can extend the selection to more than one word by dragging the selection left or right accordingly. Once you’ve got the selection right, just tap the copy button. This results in the Paste icon being displayed at the top of the keyboard (SIP) at the bottom of the page. You can then tap any other supporting control to change focus, and then tap the Paste icon to paste the copied text. At this point, the Paste icon disappears, but don’t worry, if you want to paste the same text again somewhere else just wipe left to right where the Paste icon used to be and it will re-appear.

paste

The copy and paste feature is also a global feature, so you can copy text in one application, open a new application, and then paste the copied text. This has particular advantage for applications that provide integration with web services that don’t support OAUTH or a similar convenient authentication mechanism and require an API key. You can navigate the user to the appropriate web page and instruct them to copy, and then paste their API key into your application.

So, What’s the API for Copy and Paste?

There is absolutely no API for the copy and paste feature (for now at least). I’m sure the stock answer is something to do with security, but we’ve got a clipboard API for “full fat” Silverlight and desktop applications, so I’m sure it will come in time.

If you already have an application in the Marketplace that has TextBox, PasswordBox, or WebBrowser controls in it, then you do not need to do anything to that application for it to get copy and paste support. Equally, you don’t need to do anything to enable copy and paste in new applications either. The copy and paste feature is an operating system update that users get on their devices and does not require an update to your code. If, however, you have areas of your application that you want to be read-only, but you want the user to be able to copy them (such as an API key), then you can use a TextBox with the IsReadOnly property set to true to achieve this.

The CopyTextBlock Style

Although it’s simple enough to set IsReadOnly to true on a regular TextBox, this doesn’t provide a great user experience for the user because it still looks like a TextBox. If you want a TextBlock that the user can copy from, then you can use the following Style for a TextBox instead, which not only makes it look like a TextBlock, but also removes 75% of the visuals, so is more efficient.

&lt;Style x:Key=&quot;CopyTextBlock&quot; TargetType=&quot;TextBox&quot;&gt;
    &lt;Setter Property=&quot;Background&quot; Value=&quot;Transparent&quot;/&gt;
    &lt;Setter Property=&quot;BorderBrush&quot; Value=&quot;{x:Null}&quot;/&gt;
    &lt;Setter Property=&quot;BorderThickness&quot; Value=&quot;0&quot;/&gt;
    &lt;Setter Property=&quot;FontFamily&quot;
            Value=&quot;{StaticResource PhoneFontFamilyNormal}&quot;/&gt;
    &lt;Setter Property=&quot;FontSize&quot;
            Value=&quot;{StaticResource PhoneFontSizeNormal}&quot;/&gt;
    &lt;Setter Property=&quot;Foreground&quot;
            Value=&quot;{StaticResource PhoneForegroundBrush}&quot;/&gt;
    &lt;Setter Property=&quot;IsReadOnly&quot; Value=&quot;True&quot;/&gt;
    &lt;Setter Property=&quot;SelectionBackground&quot;
            Value=&quot;{StaticResource PhoneAccentBrush}&quot;/&gt;
    &lt;Setter Property=&quot;SelectionForeground&quot;
            Value=&quot;{StaticResource PhoneTextBoxSelectionForegroundBrush}&quot;/&gt;
    &lt;Setter Property=&quot;Margin&quot; Value=&quot;0&quot;/&gt;
    &lt;Setter Property=&quot;Padding&quot; Value=&quot;0&quot;/&gt;
    &lt;Setter Property=&quot;Template&quot;&gt;
        &lt;Setter.Value&gt;
            &lt;ControlTemplate TargetType=&quot;TextBox&quot;&gt;
                &lt;Grid Background=&quot;Transparent&quot;&gt;
                    &lt;VisualStateManager.VisualStateGroups&gt;
                        &lt;VisualStateGroup x:Name=&quot;CommonStates&quot;&gt;
                            &lt;VisualState x:Name=&quot;Normal&quot;/&gt;
                            &lt;VisualState x:Name=&quot;MouseOver&quot;/&gt;
                            &lt;VisualState x:Name=&quot;Disabled&quot;/&gt;
                            &lt;VisualState x:Name=&quot;ReadOnly&quot; /&gt;
                        &lt;/VisualStateGroup&gt;
                        &lt;VisualStateGroup x:Name=&quot;FocusStates&quot;&gt;
                            &lt;VisualState x:Name=&quot;Focused&quot; /&gt;
                            &lt;VisualState x:Name=&quot;Unfocused&quot;/&gt;
                        &lt;/VisualStateGroup&gt;
                    &lt;/VisualStateManager.VisualStateGroups&gt;
                    &lt;ContentControl x:Name=&quot;ContentElement&quot;
                                    BorderThickness=&quot;0&quot;
                                    HorizontalContentAlignment=&quot;Stretch&quot;
                                    Margin=&quot;{TemplateBinding Margin}&quot;
                                    Padding=&quot;{TemplateBinding Padding}&quot;
                                    VerticalContentAlignment=&quot;Stretch&quot; /&gt;
                &lt;/Grid&gt;
            &lt;/ControlTemplate&gt;
        &lt;/Setter.Value&gt;
    &lt;/Setter&gt;
&lt;/Style&gt;

First Impressions Count

SplashScreenImage_thumb[1]First impressions in Windows Phone 7 (WP7) applications are just as important as they are in real life. You only get the opportunity to make a first impression once, so make it a good one. In the case of WP7 applications, the first impression a user will get is from the splash screen. If you haven’t taken the effort to customize your splash screen, then user’s will immediately think that you haven’t taken much effort with the rest of your application.

Requirements

According to section 5.2.1 of the Windows Phone 7 Application Certification Requirements:

a. The application must render the first screen within 5 seconds after launch.
The application may provide a splash screen image in a file called SplashScreenImage.jpg in the root of the XAP package while the application is still trying to load. However, the first application screen must be rendered within the 5 second requirement even when there is a splash screen.
Microsoft recommends that the application provides a splash screen image only when it takes longer than 1 second to load the first screen.

b. Within 20 seconds after launch, the application must be responsive to user input.

Do I Need a Splash Screen Then?

You actually only need a splash screen if your application takes more than one second to load, and in fact you can dramatically increase the start-up time of your application by removing the splash screen. If your application is taking more than one second, then make sure that your splash screen gives a good impression and is visually appealing.

SplashScreenImage_thumb[3]SplashScreenImage_thumb[5]

Slow to Start Applications

If your application takes longer than 5 seconds to load and show it’s first page, then you will fail certification, so what can you do?

Prevention is Better than Cure

Well, firstly try to delay the loading of large resources and processing data until after your first page has loaded. This means avoiding doing any processing in page or view model constructors. If you wait until the page has already been navigated to, by overriding the OnNavigatedTo method, then you know that the page has been loaded.

public class PageViewModel
{
    public IsDataLoaded { get; set; }
    public void LoadData()
    {
        if (!this.IsDataLoaded)
        {
            // Do what you need to do to load data.
            this.IsDataLoaded = true;
        }
    }
}

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        this.ViewModel = new PageViewModel();
        InitializeComponent();
    }

    private PageViewModel ViewModel
    {
        get { return this.DataContext as PageViewModel; }
        set { this.DataContext = value; }
    }

    protected override OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        this.ViewModel.LoadData();
    }
}


Showing a Splash Screen for Longer than 5 Seconds

If you need to show a splash screen for longer, then you might be tempted to create a separate page (SplashScreen.xaml for example), and then navigate to this page as your first page, display the same splash screen image on it while you do your loading, then navigate to your main page. However, don’t be tempted; this will introduce more problems with it solves as the page will exist in the page stack and when the user backs out of your application they’ll go through your splash screen, which will feel awkward at best.

A better approach would be to implement a an overlay on your main page that is shown by default, and then hidden when the loading has finished. One option for your overlay is to use the SplashScreenImage.jpg in an Image control, so that the transition to the first page is seamless to the user. You then use the OnNavigatedTo override for your page to kick off your resource loading, data handling, etc. that is taking a long time to load, and once it’s complete you can then hide the overlay.

So, the XAML for your page would look like something like this:

&lt;phone:PhoneApplicationPage
    x:Class=&quot;DerekLakin.WP7Trenches.Splash.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    xmlns:phone=&quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&quot;
    xmlns:shell=&quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    SupportedOrientations=&quot;Portrait&quot; Orientation=&quot;Portrait&quot;
    mc:Ignorable=&quot;d&quot; d:DesignHeight=&quot;768&quot; d:DesignWidth=&quot;480&quot;
    shell:SystemTray.IsVisible=&quot;False&quot;&gt;
    &lt;Grid x:Name=&quot;LayoutRoot&quot;&gt;
        // Your normal page content goes here.

        &lt;Image x:Name=&quot;_overlay&quot; Source=&quot;/SplashScreenImage.jpg&quot; /&gt;
    &lt;/Grid&gt;
&lt;/phone:PhoneApplicationPage&gt;

Landscape Orientation

NOTE: You really should consider adding full support for the landscape orientation,especially for pages that accept text input because some devices have a hardware keyboard that is landscape oriented. You will alienate your users very quickly if you force them to enter text sideways!

Setting shell:SystemTray.IsVisible="False" will ensure that your page is full screen, so the user will not see any visual difference between the loaded splash screen and your splash overlay. You also need to ensure that the Orientation is set to Portrait because WP7 always shows splash screens in this orientation. Also, don’t worry if the designer doesn’t show the splash image and shows the "blue squiggly" for the Source property on the image; trust me it works! Once you’ve loaded your data and you hide your overlay, you can enable the system tray and landscape orientation if necessary.

The code-behind in your main page will look something like this:

using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace DerekLakin.WP7Trenches.Splash
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        protected override OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigated(e);

            // Start your data loading here. A BackgroundWorker
            // might be useful for this.
            // When it's done, call the LoadComplete method.
        }

        private void LoadComplete()
        {
            this._overlay.Visibility = Visibility.Collapsed;
            this.SupportedOrientations =
                SupportedPageOrientation.PortraitOrLandscape;

            // Uncomment the following line if you want the system tray.
            // SystemTray.IsVisible = true;
        }
    }
}



Kicking it Up a Notch

Toolkit Reference

NOTE: If you have installed the Silverlight Toolkit you may find that adding a reference in your WP7 project results in a reference to this location even if you’ve actually added the library from a different location. I get this all the time because I download and build the latest from Codeplex in a different location. To fix this, just copy the assembly to a location within your solution hierarchy and add a <HintPath /> element to the assembly reference in the XML for the .csproj file. The value is a relative path from the project folder.

If you really want to engage the user while your application loads, and to show them that your application is still doing something, you could add an animation or progress bar on your splash overlay. My personal preference here is an indeterminate progress bar because it’s a common busy indicator throughout WP7 applications and the operating system. However, if you have an animation that fits in with your application and is visually engaging then you should definitely use that. For example, the Flickr application animates the blue and pink circles that form the logo.

To add a progress bar to your splash overlay, I highly recommend using the PerformanceProgressBar from the Silverlight Toolkit for WP7 because it overcomes an issue with the default progress bar and provides much better performance (hence the name!) by running on the compositor thread instead of the UI thread. So you’ll need to add a reference to Microsoft.Phone.Controls.Toolkit.dll, and then add an XML namespace reference for the Microsoft.Phone.Controls namespace. Your overlay XAML will then look like the following:

&lt;phone:PhoneApplicationPage
    x:Class=&quot;DerekLakin.WP7Trenches.Splash.MainPage&quot;
    xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
    xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
    xmlns:phone=&quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone&quot;
    xmlns:shell=&quot;clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone&quot;
    xmlns:toolkit=&quot;clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit&quot;
    xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
    xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
    mc:Ignorable=&quot;d&quot; d:DesignWidth=&quot;480&quot; d:DesignHeight=&quot;768&quot;
    FontFamily=&quot;{StaticResource PhoneFontFamilyNormal}&quot;
    FontSize=&quot;{StaticResource PhoneFontSizeNormal}&quot;
    Foreground=&quot;{StaticResource PhoneForegroundBrush}&quot;
    SupportedOrientations=&quot;Portrait&quot; Orientation=&quot;Portrait&quot;
    shell:SystemTray.IsVisible=&quot;False&quot;&gt;
    &lt;Grid x:Name=&quot;LayoutRoot&quot; Background=&quot;Transparent&quot;&gt;
        // Your normal page content goes here.
        &lt;Image x:Name=&quot;_overlay&quot; Source=&quot;/SplashScreenImage.jpg&quot; /&gt;
        &lt;toolkit:PerformanceProgressBar x:Name=&quot;_progress&quot;
                                        VerticalAlignment=&quot;Center&quot;
                                        IsIndeterminate=&quot;True&quot; /&gt;
    &lt;/Grid&gt;
&lt;/phone:PhoneApplicationPage&gt;

In this example the progress bar will use the accent color that the user has specified on their device. If there is a possibility that this could be difficult to see on top of your splash screen image, then you can force a particular color by specifying it in the Foreground property.

You then need to update the LoadComplete method in your code-behind to additionally hide the progress bar on completion as shown below.

private void LoadComplete()
{
    this._overlay.Visibility = Visibility.Collapsed;
    this._progress.Visibility = Visibility.Collapsed;

    this.SupportedOrientations =
        SupportedPageOrientation.PortraitOrLandscape;

    // Uncomment the following line if you want the system tray.
    // SystemTray.IsVisible = true;
}

Wrapping Up

In summary:

  • NEVER use the default splash screen.
  • If you don’t need one, don’t use a splash screen and your application will load even faster.
  • If you need a splash screen:
    • Be imaginative and create a visually appealing one.
    • Use the same image in an overlay on the first page if your app takes longer than 5 seconds to load.
    • Consider adding a progress bar or animation to show the user your app is doing something.
  • Your app still MUST be responsive to user input within 20 seconds no matter how flashy your splash screen is.