IT tutorials
 
Mobile
 

Windows Phone 7 Advanced Programming Model : Building a Photo Extras Application

1/11/2013 11:24:37 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

Developers always ask about ways to integrate with the underlying platform. This is especially true for a mobile device where mobile devices users want to perform actions with as little effort as possible. One popular use case is manipulating pictures taken with the built-in camera. Many applications allow photo manipulation directly on the device so integrating these application as much as possible to the Pictures Hub benefits the end-user.

Integrated experiences are a key differentiator for Windows Phone 7 and this is extended to developers as well. You can build applications that integrate with the Pictures hub such that your application can be launched directly from the Extras menu.

A Photos Extra application is accessible from within the Pictures hub Single Photo Viewer (SPV). When in the SPV, swipe up the Application Bar to expose the extras... menu item to launch a Photo Extra application to work on the currently displayed image. Note that images are the only media type that can be added to the Media Library, so once a Photos Extra performs its magic on an image, it can be saved back to the media library to be shared with others. Figure 6-9 shows the Photos Extra UI.

Figure 1. Photos Extra UI

The next section covers how to create a Photos Extra application.

1. Creating a Photos Extra App

This section covers how easy it is to integrate with the Pictures hub. Building a Photos Extra application includes the following two major steps:

  • Creating the Extras.xml file

  • Retrieving the selected photo

We will turn this project into a Photos Extra App and use MVVM Light as part of the sample. We will take advantage of messaging to communicate between the image editing View named ImageEditorView.xamland the backing ViewModel class named PictureEditingViewModel.cs. We also will use a few type converters as well. Fist we need to edit the project so that it shows up in the Photos Extra menu. The next section covers how to create the Extras.xml file.

1.1. Extras.xml File

The Extras.xml file is pretty easy to create. Here are its contents:

<Extras>
  <PhotosExtrasApplication>
    <Enabled>true</Enabled>
  </PhotosExtrasApplication>
</Extras>

Run the application to test that the WP7 Book Photos Extra is added to the Extras menu when in the Single Picture Viewer in the Pictures hub. When selected, the application just launches normally and doesn't present an editing mode but the test is successful with the application appearing in the menu. The next section covers how to capture the current picture.

1.2. Retrieving the Selected Photo

Retrieving the selected photo is performed in the OnNavigatedTo method override of the application. A set of parameters are passed in when the application is launched from the Single Photo Viewer in the Pictures hub. This allows the application to know when it is launched as a Photos Extra or when the application is simply launched from the application list or Start screen tile if pinned to the Start screen because no query parameters are present.

To retrieve the query parameters, you use the NavigationContext.QueryString property. The QueryString object is a Dictionary<string, string> object. Look for the pre-defined QueryString["token"] to know that the application was launched as a Photos Extra. Use the query value to also obtain a handle to the image.

To get started, we override OnNavigatedTo in Main.xaml.cs in order to capture the query string value to set the correct picture on PictureEditingViewModel.PictureToEdit property. Listing 1 has the code for PhotosExtraAppMainPage.xaml.cs.

Example 1. PhotosExtraApp MainPage.xaml.cs Code File
using System;
using System.Collections.Generic;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework.Media;

namespace PhotosExtraApp
{
  public partial class MainPage : PhoneApplicationPage
  {
    // Constructor
    public MainPage()
    {
      InitializeComponent();
    }

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
      base.OnNavigatedTo(e);
      //Process query string
      IDictionary<string, string> queryStrings = this.NavigationContext.QueryString;
      if (NavigationContext.QueryString.Count > 0 &&
        NavigationContext.QueryString.ContainsKey("token"))
      {
        MediaLibrary library = new MediaLibrary();
        Picture picture = library.GetPictureFromToken(queryStrings["token"]);
        //Remove this query string item so that when the user clicks
        //"back" from the ImageEditorView page the app doesn't loop back
        //over to the ImageEditorView in an endless loop of navigation because
        //the query string value is still present and picked up by
        //MainPage.OnNavigateTo each time...
        NavigationContext.QueryString.Remove("token");

        //Send Message with Picture object
        SetPictureAndNavigate(picture);
      }

					  

}

    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
      ListBox lb = sender as ListBox;
      SetPictureAndNavigate(lb.SelectedItem as Picture);
    }

    void SetPictureAndNavigate(Picture picture)
    {
      Messenger.Default.Send<Picture>(picture, "PictureToEdit");
      NavigationService.Navigate(new Uri("/ImageEditorView.xaml", UriKind.Relative));
    }
  }
}

					  

The query string value for the token parameter is obtained and the MediaLibrary.GetPictureFromToken method is called to obtain the correct image from the Picture hub. The picture is passed to the SetPictureAndNavigate method shown in Listing 6-9. This same method is called when an image is selected from the ListBox in MainPage.xaml via the ListBox_SelectionChanged method also in Listing 1.

Notice in the SetPictureAndNavigate method, it uses the MVVM Light Messenger.Default.Send to pass the picture as a message. The message is registered for and received in the PictureEditingViewModel class constructor in this line of code:

Messenger.Default.Register<Picture>(
  this, "PictureToEdit",
  (picture) => { PictureToEdit = picture; });

The PictureEditorView.xamlView databinds to the PictureEditingViewModel so that the Image control on that page can data bind to the PictureEditingViewModel.PictureToEdit property. This allows the UI to data bind to a ViewModel without directly accessing the ViewModel by using MVVM Light Toolkit Messaging.

Let's finish discussing the MainPage.xaml functionality before diving further into the picture edit page. The ListBox in MainPage.xaml data binds to the List<Picture> Pictures property in the MainViewModel class. The interesting part of the MainViewModel class is loading the images:

private void CreateDataCollections()
{
  Pictures = new List<Picture>();
  Picture picture = null;
  for (int i = 0; i < _mediaLibrary.Pictures.Count; i++)
  {
    picture = _mediaLibrary.Pictures[i];
    Pictures.Add(picture);
    if (i > 30)
      break;
  }
}

The CreateDataCollections method is hard coded to just load the first 30 pictures found into the MainViewModel.Pictures property. Figure 2 shows the MainPage.xaml UI with sample images from the Emulator rendered in a basic data template that shows the name, the image, and the album it is from.

Figure 2. PhotosExtra main page UI

The ListBox data binds to the List<Picture> Pictures collection. The data template includes an Image control. It leverages a value converter named ImageSourceConverter that calls Picture.GetImage() and sets it on the Source property for the Image control in the Data Template. Picture.GetThumbnail would be a better choice for the ListBox template, because it is a small image but we use the same converter when displaying the image on the edit screen and GetImage returns the full image and so looks better when full screen.

MainPage.xaml only displays when launched from the App List. When an image is touched, it opens to the picture editing View named PictureEditorView.xaml. When launched from the Photos Extra menu with the QueryStrings value present, the application goes straight to the picture editing view as shown in Figure 3.

Figure 3. PhotosExtra picture editing UI

Notice that in both Figure 6-10 and Figure 6-11 that the name does not include the extension. The TextBlock data binds to the Picture.Name property that includes the extension but it is parsed out. This is accomplished by a simple value converter named ImageNameConverter that has a simple line of code to obtain just the name portion:

return ((string)value).Split('.')[0];

Notice also that in Figure 6-11, when the UI is in Landscape mode the text title disappears to maximize space for image viewing and editing. This is also achieved via a value converter. The TextBlock's Visibility property Element data binds to the Orientation of the Page. The value converter sets Visibility to Collapsed if the phone is in Landscape mode. Otherwise the TextBlock's Visibility is configured to Visible. The PictureEditorView data binds to the PictureEditingViewModel class shown in Listing 2.

Example 2. PictureEditingViewModel.cs Code File
using System.IO;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Xna.Framework.Media;

namespace PhotosExtraApp.ViewModel
{
  public class PictureEditingViewModel : ViewModelBase
  {
    private MediaLibrary mediaLibrary;

    public PictureEditingViewModel()
    {
      mediaLibrary = new MediaLibrary();

      //Register to receive message with picture object from Picture Hub
      //This message is sent from MainPage.xaml.cs in OnNavigateTo
      Messenger.Default.Register<Picture>(
       this, "PictureToEdit",
       (picture) => { PictureToEdit = picture; });

      //Instantiate Commands
      SaveImageCommand = new RelayCommand(
        () => SaveImage());

      SaveImageAsCommand = new RelayCommand<string>(
        param => SaveImageAs(param));

      RevertToSavedImageCommand = new RelayCommand(
        () => EditImage());
      EditImageCommand = new RelayCommand(
        () => RevertToSavedImage());
    }

    #region Image State
    public const string PictureToEditPropertyName = "PictureToEdit";
    private Picture _pictureToEdit = null;
    public Picture PictureToEdit
    {
      get
      {
        return _pictureToEdit;
      }

      set
      {
        if (_pictureToEdit == value)
        {
          return;
        }
        var oldValue = _pictureToEdit;
        _pictureToEdit = value;
        RaisePropertyChanged(PictureToEditPropertyName);
      }
    }


    public const string ModifiedPicturePropertyName = "ModifiedPicture";
    private WriteableBitmap _modifiedPicture = null;

					  

public WriteableBitmap ModifiedPicture
    {
      get { return _modifiedPicture; }
      set
      {
        if (_modifiedPicture == value)
        { return; }
        var oldValue = _modifiedPicture;
        _modifiedPicture = value;
        RaisePropertyChanged(ModifiedPicturePropertyName);
      }
    }

    //Property to data bind to for SaveAs input UI
    //Used for SaveAs command
    public const string ImageSaveAsNamePropertyName = "ImageSaveAsName";
    private string _imageSaveAsName = null;
    public string ImageSaveAsName
    {
      get { return _imageSaveAsName;}
      set
      {
        if (_imageSaveAsName == value)
        { return; }
        var oldValue = _imageSaveAsName;
        _imageSaveAsName = value;
        RaisePropertyChanged(ImageSaveAsNamePropertyName);
      }
    }

    public const string ImageIsDirtyPropertyName = "ImageIsDirty";
    private bool _imageIsDirety = false;
    public bool ImageIsDirty
    {
      get { return _imageIsDirety; }
      set
      {
        if (_imageIsDirety == value)
        { return; }

        var oldValue = _imageIsDirety;
        _imageIsDirety = value;
        RaisePropertyChanged(ImageIsDirtyPropertyName);
      }
    }
    #endregion

    #region Image Actions for RelayCommand Objects
    private void EditImage()
    {
      //Editing, unsaved changes pending
      ImageIsDirty = true;
    }

					  

//View must set the writable bitmap area
    //prior to executing this command
    //This Save action takes a new name
    private void SaveImageAs(string saveAsName)
    {
      using (MemoryStream jpegStream = new MemoryStream())
      {
        //Tell the UI to update the WriteableBitmap property
        Messenger.Default.Send<bool>(true, "UpdateWriteableBitmap");
        ModifiedPicture.SaveJpeg(jpegStream, ModifiedPicture.PixelWidth,
          ModifiedPicture.PixelHeight, 0, 100);
        //Update current Picture to reflect new modified image
        PictureToEdit = mediaLibrary.SavePicture(saveAsName, jpegStream);
        //Saved, not editing
        ImageIsDirty = false;
      };
    }

    //View must set the writable bitmap area
    //prior to executing this command
    //This save action overwrites existing image
    private void SaveImage()
    {
      using (MemoryStream jpegStream = new MemoryStream())
      {
        //Tell the UI to update the WriteableBitmap property
        Messenger.Default.Send<bool>(true, "UpdateWriteableBitmap");
        ModifiedPicture.SaveJpeg(jpegStream, ModifiedPicture.PixelWidth,
          ModifiedPicture.PixelHeight, 0, 100);
        //Update current Picture to reflect new modified image
        PictureToEdit = mediaLibrary.SavePicture(PictureToEdit.Name, jpegStream);
        //Saved, not editing
        ImageIsDirty = false;
      };
    }

    //PictureEditingView registers to receive this message
    //It would clear out any edits at the UI level.
    private void RevertToSavedImage()
    {
      Messenger.Default.Send<bool>(true, "UndoImageChanges");
    }
    #endregion

    #region Image Editing Commmands
    public RelayCommand SaveImageCommand { get; private set; }
    public RelayCommand<string> SaveImageAsCommand { get; private set; }
    public RelayCommand EditImageCommand { get; private set; }
    public RelayCommand RevertToSavedImageCommand { get; private set; }
    #endregion
  }
}

					  

The PictureEditingViewModel class has two primary data properties: PictureToEdit of type Picture and the ModifiedPicture of type WriteableBitmap. The idea is to display the selected picture to be modified in an Image control.

The user can then edit the image in the UI. The modifications under the covers would result in additional Silverlight controls added to the XAML with the Grid WritableBitMapSourceArea as the top-level parent. When the user clicks save, the Grid is passed into the WriteableBitmap to turn it into a bitmap image.

You can pass any UIElement into the WriteableBitmap.Render method and it will turn the element and its children into an image. In the SaveImageCommand (SaveImage()) and SaveImageAsCommand (SaveImageAs()) commands, a message is sent to the UI to update the ModifiedPicture property on the VM prior to saving. We could do this in a way without tying the View to the ViewModel via additional messages, but for our example this is sufficient.

The PictureEditingViewModel class also sends a message to the UI to ask the View to undo modifications to the image. Listing 3 has the PictureEditorView code-behind file.

Example 3. PictureEditorView .xaml.cs Code File
using System.Windows.Controls;
using GalaSoft.MvvmLight.Messaging;
using Microsoft.Phone.Controls;
using PhotosExtraApp.ViewModel;

namespace PhotosExtraApp
{
  /// <summary>
  /// Description for ImageEditorView.
  /// </summary>
  public partial class PictureEditorView : PhoneApplicationPage
  {
    PictureEditingViewModel vm;
    /// <summary>
    /// Initializes a new instance of the ImageEditorView class.
    /// </summary>
    public PictureEditorView()
    {
      InitializeComponent();

      vm = DataContext as PictureEditingViewModel;

      //Register for message to undo changes
      Messenger.Default.Register<bool>(
        this, "UndoImageChanges",
        (param) => UndoImageChanges());

      Messenger.Default.Register<bool>(

					  
this, "UpdateWriteableBitmap",
        (param) => UpdateWriteableBitmap());
    }

    private void UpdateWriteableBitmap()
    {
      //Update WriteableBitmap so it is ready to save
      vm.ModifiedPicture.Render(WriteableBitmapSourceArea, null);
    }

    private void UndoImageChanges()
    {
      //Undo Image changes
      //Reset WriteableBitmapSourceArea Grid to just hold
      //the original image content only
      Image img = ImageToEdit;
      WriteableBitmapSourceArea.Children.Clear();
      WriteableBitmapSourceArea.Children.Add(img);
    }

    private void EditAppBarBtn_Click(object sender, System.EventArgs e)
    {
      vm.EditImageCommand.Execute(null);
    }

    private void saveAppBarBtn_Click(object sender, System.EventArgs e)
    {
      vm.SaveImageCommand.Execute(null);
    }

    private void SaveAsAppMenItem_Click(object sender, System.EventArgs e)
    {
      vm.SaveImageAsCommand.Execute(vm.ImageSaveAsName);
    }

    private void RevertToLastSaveMenuItem_Click(object sender, System.EventArgs e)
    {
      vm.RevertToSavedImageCommand.Execute(null);
    }
  }
}				  

This code walkthrough demonstrates how to set up all the infrastructure for a picture modifying Photos Extra application. It does not actually perform edits, that we leave to the enterprising reader to build the next great Photos Extra application.
 
Others
 
- IPad : Working with Contacts - Adding Contacts from E-mails, Sending an E-mail Message from Contacts
- IPad : Working with Contacts - Adding a Photo to Contacts, Searching Your Contacts
- Enter Java ME on Symbian OS : Which APIs Are Supported?
- Enter Java ME on Symbian OS : Running a MIDlet on a Symbian Smartphone
- BlackBerry Bold 9700 and 9650 Series : Fixing Problems - Updating the BlackBerry Operating System
- BlackBerry Bold 9700 and 9650 Series : Fixing Problems - Understanding Your Wireless Data Connection
- Android Application Development : The ApiDemos Application (part 2) - Adding Your Own Examples to ApiDemos
- Android Application Development : The ApiDemos Application (part 1) - Application Setup in the Manifest File, Finding the Source to an Interesting Example
- iphone Programming : Adding Missing Features (part 3) - Changing the Display Name, Enabling Rotation
- iphone Programming : Adding Missing Features (part 2) - Adding a Launch Image
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us