Windows Phone 7 beta: Launcher and Chooser Tasks Cludge

Firstly I have to apologise to any readers who experienced issues viewing my blog over the last 72 hours. This was a result of my awesome (not!) hosting provider webhost4life. Anyhow hopefully the issues have been resolved and life can continue.

In my previous post (Windows Phone 7 beta- Who Killed My Application) I talked about what happens when your application goes into the background. Specifically that in the current bits your application will be terminated. Now in actual fact the Windows Phone developer contract doesn’t state this, it only says that your application may be terminated any time between when your application receives a Deactivated event and when it receives an Activated event. In the case where it is terminated (which is always the case in the current dev bits) when the user presses the Back button your application will be relaunched and the Activated event raised (not the Launching event).

Here’s another scenario where you may be wondering what’s going on with Visual Studio. In your application you want to use the CameraCaptureTask to take a photo. You create an instance of the CameraCaptureTask, add an event handler for the Completed event (note that this is different from the April CTP where you overrode a method on the base class) and then call the Show method. For example the following code launches the CameraCaptureTask and then sets the photo as the source of an Image control.

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

namespace WindowsPhoneTasks
{
    public partial class MainPage : PhoneApplicationPage
    {
        CameraCaptureTask cameraTask = new CameraCaptureTask();
     
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            cameraTask.Completed += new EventHandler<PhotoResult>(cameraTask_Completed);
        }

        void cameraTask_Completed(object sender, PhotoResult e)
        {
            var source = new BitmapImage();
            source.SetSource(e.ChosenPhoto);

            this.PhotoImage.Source = source;
        }

        private void TakeAPhotoButton_Click(object sender, RoutedEventArgs e)
        {
            cameraTask.Show();
        }
    }
}

When you run this you will notice something weird. The following screenshot sequence illustrates this. Initially the emulator is at the Start screen (1). You run the application from Visual Studio and then you click the Take Photo button (2). This launches the camera capture dialog (3) and you’ll notice that your application has been terminated – this dialog is a bit buggy at the moment so you may need to click around the screen in order to find the button to take a picture; it’s in the top right corner! When you click “accept” you will see a blank screen(4). If you recall from my previous post, this is what happened when the user clicked the Back button to return to your application. You’re seeing a blanks screen because your application isn’t there any more. Press F5 or Run your application from Visual Studio and the Completed event will be fired, displaying the photo in the Image (5).

 

image[4]

Here’s the cludge (as if having to restart Visual Studio wasn’t enough of a cludge): In order for the Completed event to work the instance of the CameraCaptureTask has to be an instance variable where the event handler is wired up in the constructor of the page. As you can imagine there is some additional logic that gets performed as part of the add event handler operation (using Reflector):

 

public event EventHandler<TTaskEventArgs> Completed
{
    add
    {
        if ((this._completed == null) || (Array.IndexOf<Delegate>(this._completed.GetInvocationList(), value) == -1))
        {
            this._completed = (EventHandler<TTaskEventArgs>) Delegate.Combine(this._completed, value);
            InvokeReturningEventArgs args = null;
            if (ChooserListener.IsChooserCompletePending(this._genericChooser, value, out args))
            {
                this.OnInvokeReturned(args.returnBuffer, value);
            }
        }
    }
    remove
    {
        this._completed = (EventHandler<TTaskEventArgs>) Delegate.Remove(this._completed, value);
    }
}

Leave a comment