03 December 2011

Re-imagining the behavior to show the Windows Phone 7 camera as background

This blog turns out not only to be a collection of how-to samples but also a record of my evolution as a Windows Phone 7 developer. At the end of my previous post, Safe event detachment base class for Windows Phone 7 behaviors, I promised a usage example and I decided to re-implement the behavior to show the Windows Phone 7 camera as background using the SafeBehavior as a base class. This makes the code considerable easier.

The base setup of the re-implemented behavior is pretty simple:

using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Navigation;
using Microsoft.Devices;
using Microsoft.Phone.Controls;

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior that shows a camera view on the background of a panel
  /// </summary>
  public class CameraViewBackgroundBehavior : SafeBehavior<Panel>
  {

    private PhotoCamera camera;
    private VideoBrush backgroundBrush;

    public CameraViewBackgroundBehavior()
    {
      ListenToPageBackEvent = true;
    }
  }
}

Note this behavior needs to detect the user navigating back to the page – this in necessary because we need to do something with the camera.

In stead of all the song and dance for attaching and detaching events using the snippet I published earlier, it’s now a matter of overriding the OnSetup and OnCleanup methods to initialize the camera:

protected override void OnSetup()
{
  if (camera == null)
  {
    camera = new PhotoCamera();
    ParentPage.OrientationChanged += ParentPageOrientationChanged;
  }

  // Create a video brush with the right parameters
  backgroundBrush = new VideoBrush
                      {
                        Stretch = Stretch.UniformToFill,
                        AlignmentX = AlignmentX.Left,
                        AlignmentY = AlignmentY.Top
                      };

  // Set the video brush to the background of the panel 
  // and and do an initial display
  AssociatedObject.Background = backgroundBrush;
  backgroundBrush.SetSource(camera);
  SetVideoOrientation(ParentPage.Orientation);
}

protected override void OnCleanup()
{
  ParentPage.OrientationChanged -= ParentPageOrientationChanged;
  camera.Dispose();
  camera = null;
}

This behavior also needs to do some action when the user actually navigates back to the page, which you can do by override the OnParentPageNavigated method - in this case, re-initializing the whole behavior

/// <summary>
/// Fired whe page navigation happens
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected override void OnParentPageNavigated(object sender, NavigationEventArgs e)
{
  // Re-setup when this page is navigated BACK to
 if( IsNavigatingBackToBehaviorPage(e))
 {
   if (camera != null)
   {
     OnCleanup();
     OnSetup();
   }
  }
}

The actual implementation of showing the camera background has hardly changed, and is only mentioned here for the sake of completeness:

private void ParentPageOrientationChanged(object sender, OrientationChangedEventArgs e)
{
  SetVideoOrientation(e.Orientation);
}

/// <summary>
/// Sets background video brush parameters based upon page orientation
/// </summary>
/// <param name="orientation"></param>
private void SetVideoOrientation(PageOrientation orientation)
{
  System.Diagnostics.Debug.WriteLine("Switching to {0}", orientation);
  switch (orientation)
  {
    case PageOrientation.PortraitUp:
      backgroundBrush.Transform = 
        new CompositeTransform { Rotation = 90, TranslateX = 480 };
      break;
    case PageOrientation.LandscapeLeft:
      backgroundBrush.Transform = null;
      break;
    case PageOrientation.LandscapeRight:
      if (Microsoft.Phone.Shell.SystemTray.IsVisible )
      {
        backgroundBrush.Transform = 
          new CompositeTransform { Rotation = 180, TranslateX = 728, TranslateY = 480 };
      }
      else
      {
        backgroundBrush.Transform = 
            new CompositeTransform { Rotation = 180, TranslateX = 800, TranslateY = 480 };
      }
      break;
  }
}

As this post demonstrated, using the SafeBehavior as a base class makes life a lot easier than implementing the whole pattern over and over again, even when using a snippet.

Code is part of the the #wp7nl library on codeplex and can be found here

No comments: