wp7appdevelopment

Adventures in Windows Phone app development

Tag Archives: c#

Tombstoning in Windows Phone 8 Apps

I have a simple Windows Phone game, and my way of dealing with tombstoning is to just start a new game. To do this, I need to first detect that that app was tombstoned. I check for this every time I navigate to a page. If tombstoning has occurred, I navigate to the main page of my app/game and delete the navigation back stack, effectively starting fresh.

NOTE: Because my game is so simple, I don’t need to bother with saving the game state or any data. Most apps will want to save info instead of just starting a new game.

[1] Create a entry in the isolated storage to store a boolean value of whether the app has been tombstoned.

I use a helper class, AppSettings, to store and retrieve values from Isolated Store. See this post for more info. The default value is false.

const string WasTombstonedKeyName = "WasTombstoned";
const bool WasTombstonedDefault = false;
 public bool wasTombstoned
        {
            get
            {
                return GetValueOrDefault<bool>(WasTombstonedKeyName, WasTombstonedDefault);
            }
            set
            {
                AddOrUpdateValue(WasTombstonedKeyName, value);
                Save();
            }
        }

[2] You can check if an app has been activated in the Application_Activated() method of App class (App.xaml.cs). This method is executed when an application is activated (brought to the foreground). It does not execute when the application is first launched.

Add the following code to set the value of our WasTombstoned flag in the (isolated store) to either true or false:

 private void Application_Activated(object sender, ActivatedEventArgs e)
        {
            AppSettings mySettings = new AppSettings();

            if (e.IsApplicationInstancePreserved)
                mySettings.WasTombstoned = false;
            else
                mySettings.WasTombstoned = true;
        }

[3] Modify the OnNavigatedTo method of your MainPage.xaml.cs. You’ll want to clear the WasTombstoned flag, and also clear the navigation backstack.

 protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            // Remove entries from the backstack, so that a back key press exits the app.
            try
            {
                while (NavigationService.CanGoBack)
                    NavigationService.RemoveBackEntry();
            }
            catch
            {
            }

            // clear the wasTombstoned flag
            mySettings.wasTombstoned = false;

            base.OnNavigatedTo(e);
        }

[4] On all other pages, edit the OnNavigatedTo method to check for Tombstoning and return to the MainPage if it occurred.

 protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            AppSettings myAppSettings = new AppSettings();

            base.OnNavigatedTo(e);

            if (myAppSettings.wasTombstoned)
                NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
        }

[5] Testing
Assuming you are using Visual Studio to build your app, the easiest way to test tombstoning is to edit the Properties:

  1. In the Solution Explorer, double-click on Properties to open that panel.
  2. Left-click on the Debug tab (left side of panel).
  3. Click the checkbox for “Tombstone upon deactivation while debugging.”

Now, when you are testing, when you leave the application (for example, when you press the windows key or search key on the bottom of the phone) and then return to the application (for example, by pressing the back key), the application will have been tombstoned.

Scrolling to the Selected Item Listbox

If you’re developing an Windows Phone app, you will often use a ListBox to display information. Here’s how to set the selected item programmatically and scroll the selected item into view. This example assumes you’re working with C# and Silverlight.

Selecting an item in a listbox

You can select a specific item in a ListBox using the SelectedIndex property. For example, to select the sixth item (index=5) in a list, use the following in your C# code:

  myList.SelectedIndex = 5;

Scrolling Selected Item into View

The ListBox.ScrollIntoView method can be used to scroll to a particular place in a ListBox. For example, to scroll down your ListBox items so that the selected item is displayed, use the following in your C# code:

   myList.ScrollIntoView(myList.SelectedItem);

One note — if you’ve changed the contents of your ListBox (i.e., if the contents of your ItemsSource collection changes), you may need to call UpdateLayout() before calling ScrollIntoView():

   UpdateLayout();
   myList.ScrollIntoView(myList.SelectedItem);

References

ListBox.ScrollIntoView Method

ListBox Class

How to Make a Windows Phone 7 Vibrate (C#)

Vibrate your phone?

There are many reasons you might want to programmatically vibrate the phone during apps or games.  You might want to alert the user to an error condition, and emphasize that a button has been clicked.

The Windows Phone 7 SDK makes it easy for developers to control the vibrate function easily, using the VibrateController class. The VibrateController class is defined in the namespace Microsoft.Devices.

The following example shows how to vibrate the phone using C#:


using Microsoft.Devices;

VibrateController vibrate = VibrateController.Default;
vibrate.Start(TimeSpan.FromMilliseconds(200));

That’s all that you need to do! You can change the vibrate duration — this example uses 200 milliseconds.
Of course, common-sense best practices: don’t overdo the use of vibration, and give the user the option to disable.

References

VibrateController class documentation

Windows 8 (Win8 Metro) C#/Silverlight: Playing Sound in Apps

This example shows how to play sounds in a Windows 8 app developed using C#/Silverlight.

Updated: See Simpler Example section below.

Key steps are:

  • Create a MediaElement object
  • Read in the sound file to a stream
  • Set the source of your MediaElement object using the stream
  • Call the MediaElement.Play() method to play the sound
MediaElement _mySound = new MediaElement();
Windows.Storage.StorageFolder folder = await Package.Current.InstalledLocation.GetFolderAsync("Sounds");
Windows.Storage.StorageFile file = await folder.GetFileAsync("sound.wav");
var stream = await file.OpenmReadAsync();
mySound.SetSource(stream, file.ContentType);

mySound.Play();

Example Implementation

The following example assumes the sound files are stored in a folder named Sounds. The InitializeSound() method is called once, to read in the sound files and initialize the MediaElements. After initialization, the PlaySound() method can be called to play the sound. PlaySound() takes one argument, which is the MediaElement (sound) to be played. This example also assumes a global variable (bool _useSound) that is used to conditionally play the sound in the game.

One important note: You must set the MediaElement AutoPlay property to false before setting the Source property. This prevents the sound from playing during initialization.

        private MediaElement _cardSound = new MediaElement();
        private MediaElement _dingSound = new MediaElement();

        private void InitializeSound()
        {
            LoadSound("CardFlip.wav",  _cardSound);
            LoadSound("success.wav",  _dingSound);

        }

        private async void LoadSound(string SoundFilePath, MediaElement SoundElement)
        {
            // all sounds are stored in the Sounds folder
            try
            {
                Windows.Storage.StorageFolder folder = await Package.Current.InstalledLocation.GetFolderAsync("Sounds");
                Windows.Storage.StorageFile file = await folder.GetFileAsync(SoundFilePath);
                var stream = await file.OpenReadAsync();
                SoundElement.AutoPlay = false;
                SoundElement.SetSource(stream, file.ContentType);
            }
            catch
            {
                System.Diagnostics.Debug.WriteLine("Problem opening sound file: " + SoundFilePath);
            }
        }

        private void PlaySound(MediaElement SoundElement)
        {

            // only play sounds if the user has 'play sounds' enabled
            if (_useSound)
            {
                try
                {
                    SoundElement.Play();
                }
                catch
                {
                    System.Diagnostics.Debug.WriteLine("Problem playing sound: " + SoundElement.ToString());
                }
            }
        }

Simpler Example

Here’s a simpler way to play a sound. This works if you won’t be changing the source of the MediaElement:

  1. Add a MediaElement to your visual tree (e.g., LayoutRoot) in your XAML. 
  2. Specify the source for the MediaElement in the XAML.
  3. Call MediaElement.Play() to play the sound.

But, if you want to be able to programmatically change the source in your C# code behind, you’ll need to wait for the new media file to load before it will play. If you just change the source and then immediately call Play(), the media file won’t be loaded and it therefore won’t play.

  1. Register a handler for MediaSource.MediaOpened events.
  2. Set MediaElement.Source in your xaml.cs file.
  3. In your MediaOpened handler, call Play().

Here’s an example. Create a MediaElement object in your XAML:

 <MediaElement x:Name="sound" AutoPlay="False" />

In an initializer function (constructor, OnNavigatedTo, etc.) in your xaml.cs,  register the handler for MediaOpened events for our MediaElement:

sound.MediaOpened += sound_MediaOpened;

Add the code that changes the source file. (Note: I created a Sounds folder in my project, so my pathnames look like “ms-appx:///Sounds/mysoundfile.wma”)

        private void PlaySoundButton_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                sound.Source = new Uri("insert new file path here", UriKind.Absolute);

            }
            catch { }
        }

Add the code for the sound_MediaOpened() handler:

void sound_MediaOpened(object sender, RoutedEventArgs e)
{
    sound.Play();
}

When your code is called to change the source file, the system will go and open the specified file. Assuming it’s able to be opened with no errors, the sound_MediaOpened() method will then be called. When we call sound.Play(), our new sound file will play.

Windows 8 (Win8 Metro) C#/Silverlight: Programmatically Setting Image Source

Specifying an Image.Source

If you are developing a Windows 8 (WinRT) app using C#/XAML, you can set the source for images either using XAML or programmatically in your C# code-behind file.

Using XAML

It’s trivial to set an image’s source in the XAML using Visual Studio Express 2012. Assume you have the folder “Images” in your current project, and in this folder you have an image file named “myPic.png”. The following XAML declaration sets the Image.Source property:

  <Image Height="100" Width="100" Source="Images/myPic.png" />

Using C#

But what if you need to programmatically set the source property? Turns out that’s trivial, too — assuming you know the correct path naming.  Assume the same scenario — an “Images” folder that contains the image file “myPic.png.”


Image myImage = new Image() { Width="100", Height="100"};
myImage.Source = new BitmapImage(new Uri("ms-appx:///Images/myPic.png", UriKind.Absolute));

This code creates a new absolute URI that specifies the image file location, and then uses this Uri to create a new BitmapImage. Two important details to getting this to work:

  • You must use an Absolute pathname in the URI; relative pathnames are not supported
  • To specify the absolute pathname for resources in your project, use: “ms-appx:///folder_name/file_name

Simple, once you know the correct path to use. I had trouble finding clear documentation on this — hope this saves you some time!

Silverlight: Sound Effects

The following procedure can be used to add sound effects to Windows Phone 7 (WP7) apps developed with Silverlight/C#.

  1. Add a reference to Microsoft.Xna.Framework to your project
  2. Add the .wav files to your project and specify type=Content
  3. Add the following statements to your C# code:
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using System.Windows.Resources;
    using System.Windows.Threading;
    
  4. Add variables for your SoundEffects:
    private SoundEffect mySound;
    
  5. Add the following code to the page (class) constructor:
    
    LoadSound("Sounds/mySound.wav", out mySound);
    // Timer to simulate the XNA game loop (SoundEffect classes are from the XNA Framework)
    DispatcherTimer XnaDispatchTimer = new DispatcherTimer();
    XnaDispatchTimer.Interval = TimeSpan.FromMilliseconds(50);
    
    // Call FrameworkDispatcher.Update to update the XNA Framework internals.
    XnaDispatchTimer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
    // Start the DispatchTimer running.
    XnaDispatchTimer.Start();
    
    
  6. Add the following LoadSound method:
            private void LoadSound(String SoundFilePath, out SoundEffect Sound)
            {
                // For error checking, assume we'll fail to load the file.
                Sound = null;            try
                {
                    // Holds informations about a file stream.
                    StreamResourceInfo SoundFileInfo = App.GetResourceStream(new Uri(SoundFilePath,
                            UriKind.Relative));                // Create the SoundEffect from the Stream
                    Sound = SoundEffect.FromStream(SoundFileInfo.Stream);
                }
                catch (NullReferenceException)
                {
                    // Display an error message
                    MessageBox.Show("Couldn't load sound " + SoundFilePath);
                }
            }
    
  7. Add the following code to play the sound effect:
                try
                {
                    mySound.Play();
                }
                catch (NullReferenceException)
                {
                   MessageBox.Show("Can't play, cardSound is null.");
                }
    

    Simpler Example: No timer

    If the only XNA framework functionality used inside a Silverlight application is one or more instance of type SoundEffect, and only one single SoundEffect is played at any given time, you don’t need to set up a timer. Instead, you can just call FrameworkDispatcher.Update() before calling the Play() method.

    For example:

    
    try
    {
    FrameworkDispatcher.Update();
    mySound.Play();
    }
    catch (NullReferenceException)
    {
    MessageBox.Show("Can't play, cardSound is null.");
    }
    

    Complete Example

    The following example puts all the bits of code together. It assumes the app has the single page, MainPage.xaml, with a button that uses the Button_Click callback method. It also assumes there is a sound file named “UI_Misc15.wav” that is stored in a project subdirectory “Sounds”.
    using System;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using System.Windows.Resources;
    using System.Windows.Threading;
    
    namespace SoundDemo
    {
        public partial class MainPage : PhoneApplicationPage
        {
            private SoundEffect mySound;
    
            // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                LoadSound("Sounds/UI_Misc15.wav", out mySound);
    
                // Timer to simulate the XNA game loop (SoundEffect classes are from the XNA Framework)
                DispatcherTimer XnaDispatchTimer = new DispatcherTimer();
                XnaDispatchTimer.Interval = TimeSpan.FromMilliseconds(50);
    
                // Call FrameworkDispatcher.Update to update the XNA Framework internals.
                XnaDispatchTimer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
    
                // Start the DispatchTimer running.    
                XnaDispatchTimer.Start();
    
            }
    
            private void LoadSound(String SoundFilePath, out SoundEffect Sound)
            {
                // For error checking, assume we'll fail to load the file.
                Sound = null;
    
                try
                {
                    // Holds informations about a file stream.
                    StreamResourceInfo SoundFileInfo = App.GetResourceStream(new Uri(SoundFilePath,
                            UriKind.Relative));
    
                    // Create the SoundEffect from the Stream
                    Sound = SoundEffect.FromStream(SoundFileInfo.Stream);
                }
                catch (NullReferenceException)
                {
                    // Display an error message
                    MessageBox.Show("Couldn't load sound " + SoundFilePath);
                }
            }
    
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                try
                {
                    mySound.Play();
                }
                catch (NullReferenceException)
                {
                    MessageBox.Show("Can't play, cardSound is null.");
                }
    
            }
        }
    }
    

Using PhotoChooserTask in Silverlight/Windows Phone apps

The PhotoChooserTask launches an app that lets the user select a photo from their phone. If the user selects a photo, the app raises the Completed event and the event handler gets passes a PhotoResult object. You can access the image data through this object’s photo image stream.

    1. Include a using statement for Microsoft.Phone.Tasks in your page class (e.g, MainPage.xaml.cs):
      using Microsoft.Phone.Tasks;
    2. In your page class, include a declaration for a PhotoChooserTask:
       PhotoChooserTask photoChooserTask;
    3. In the constructor, initialize the PhotoChooserTask and add the handler for the Completed event:
      photoChooserTask = new PhotoChooserTask(); 
      photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
    4. Add the Completed handler:
      // The Completed event handler. In this example, a new BitmapImage is created and  
      // the source is set to the result stream from the PhotoChooserTask
      void photoChooserTask_Completed(object sender, PhotoResult e)
          {
              if (e.TaskResult == TaskResult.OK) {
                  System.Windows.Media.Imaging.BitmapImage bmp =
                     new System.Windows.Media.Imaging.BitmapImage(); 
                  bmp.SetSource(e.ChosenPhoto);
              }
          }
    5. Add a method to call the PhotoChooserTask. This examples assumes the task will be called after a button click:
      // In this example, the PhotoChooserTask is shown in response to a button click
      private void button1_Click(object sender, RoutedEventArgs e)
      {
          try {
              photoChooserTask.Show();
          }
          catch (System.InvalidOperationException ex) {
              // Catch the exception, but no handling is necessary.
          }
      }

Note: if the PhotoChooserTask looks like it’s not working on the device but it works fine on the emulator, disconnect your phone from the Zune software. If you’re debugging while the Zune software is running, the task will return the Cancel event and never display the photo chooser.

Complete Code Sample

public partial class MainPage : PhoneApplicationPage
{
    // Declare the PhotoChooserTask object with page scope.
    PhotoChooserTask photoChooserTask;

    // Constructor
    public MainPage()
    {
        InitializeComponent();

        // Initialize the PhotoChooserTask and assign the Completed handler in the page constructor.
        photoChooserTask = new PhotoChooserTask();
        photoChooserTask.Completed += new EventHandler<PhotoResult>(photoChooserTask_Completed);
    }

    // In this example, the PhotoChooserTask is shown in response to a button click
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        try {
            photoChooserTask.Show();
        }
        catch (System.InvalidOperationException ex) {

           // Catch the exception, but no handling is necessary.
        }
    }

    // The Completed event handler. In this example, a new BitmapImage is created and
    // the source is set to the result stream from the PhotoChooserTask
    void photoChooserTask_Completed(object sender, PhotoResult e)
    {
        if (e.TaskResult == TaskResult.OK) {
            System.Windows.Media.Imaging.BitmapImage bmp =
                new System.Windows.Media.Imaging.BitmapImage();
            bmp.SetSource(e.ChosenPhoto);
         }
    }
}

Additional References