Microsoft Surface示例之PhotoPaint
PhotoPaint是微软为Microsoft Surface给出的一个经典示例,此示例展示可在一张图片上绘图,就像Windows系统自带画图软件铅笔的效果,下面先看一下效果:



下面是代码部分:
Xaml Code:
<s:SurfaceWindow x:Class="PhotoPaint.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
xmlns:pp="clr-namespace:PhotoPaint"
Title="PhotoPaint">
<s:SurfaceWindow.Resources>
<Grid x:Key="EditButtonImage"
Width="38"
Height="38"
VerticalAlignment="Center"
Background="Transparent" >
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Pencil1"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 5.82884,16.4138L 0.172017,17.828L 1.58624,12.1711L 13.5853,0.171997L 17.828,4.41467L 5.82884,16.4138 Z M 2.50753,13.0924L 1.98912,15.1661L 2.83398,16.0109L 4.90755,15.4925L 2.50753,13.0924 Z "
Margin="0"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
<Grid x:Key="EraseButtonImage" Background="Transparent" VerticalAlignment="Center" Height="38" Width="38">
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Path"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 0.500891,21.1431L 1.87231,18.6184L 10.1914,25.9037C 10.8905,26.5158 11.9534,26.4453 12.5656,25.7463L 28.8125,7.19364L 28.8125,12.4007L 12.9586,31.4896C 11.7713,32.9192 9.64985,33.1157 8.22021,31.9283L 0.946734,25.2718C -0.482872,24.0844 0.000349879,22.4327 0.500891,21.1431 Z M 19.1382,1.0865C 20.3256,-0.343134 21.389,-0.311098 22.8186,0.876265L 28.204,5.33469L 12.4081,23.3724C 11.7959,24.0714 10.7329,24.1419 10.0339,23.5297L 2.86836,17.2547L 19.1382,1.0865 Z "
Margin="0"
Grid.Row="1"
Grid.Column="1"/>
</Grid>
</s:SurfaceWindow.Resources>
<!-- Window Content -->
<Grid>
<s:ScatterView>
<!-- Drawing Pad - InkCanvas with white background and small border -->
<s:ScatterViewItem Height="317"
Width="423"
MinWidth="293"
MaxWidth="846"
Background="{DynamicResource {x:Static s:SurfaceColors.LibraryControlManipulationAreaBackgroundBrushKey}}">
<Grid>
<!-- Row and column definitions to position content and buttons -->
<Grid.RowDefinitions>
<RowDefinition Height="7" />
<RowDefinition />
<RowDefinition Height="52" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7" />
<ColumnDefinition />
<ColumnDefinition Width="44" />
<ColumnDefinition Width="44" />
<ColumnDefinition Width="44" />
<ColumnDefinition />
<ColumnDefinition Width="7" />
</Grid.ColumnDefinitions>
<!-- The Ink Canvas -->
<Viewbox Grid.Column="1" Grid.ColumnSpan="5" Grid.Row="1" Grid.RowSpan="1" StretchDirection="Both" Stretch="Fill">
<s:SurfaceInkCanvas x:Name="DrawingPadCanvas" StrokeCollected="OnStrokeCollected" Height="263" Width="414"
Background="{DynamicResource {x:Static s:SurfaceColors.LibraryControlScrollAreaBackgroundBrushKey}}" />
</Viewbox>
<!-- Edit Mode -->
<s:SurfaceButton Name="EditModeButton" Grid.Row="2" Grid.Column="2" Padding="0" Margin="3.5,7,3.5,7" Click="EditModeClicked">
<Grid x:Name="DrawButtonImage"
Width="38"
Height="38"
VerticalAlignment="Center"
Background="Transparent" >
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Pencil2"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 5.82884,16.4138L 0.172017,17.828L 1.58624,12.1711L 13.5853,0.171997L 17.828,4.41467L 5.82884,16.4138 Z M 2.50753,13.0924L 1.98912,15.1661L 2.83398,16.0109L 4.90755,15.4925L 2.50753,13.0924 Z "
Margin="0"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
</s:SurfaceButton>
<!-- Undo Button -->
<s:SurfaceButton Grid.Row="2" Grid.Column="4" Padding="0" Margin="3.5,7,3.5,7" Click="UndoClicked">
<Grid x:Name="Undo"
Width="38"
Height="38"
Background="Transparent"
VerticalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Undo1"
Width="20"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 0.747703,0.413038L 3.56185,3.22719C 5.62339,0.955633 8.52644,-0.170475 11.3426,0.524384C 15.7386,1.60904 18.258,6.72012 16.97,11.9404C 16.3949,14.2711 15.1581,16.2295 13.5738,17.587L 12.1257,16.1389C 13.4472,15.0512 14.4955,13.4139 14.9802,11.4494C 15.9971,7.32806 14.1487,3.32765 10.8517,2.51414C 8.75505,1.99682 6.57753,2.89283 5.00835,4.67369L 7.92133,7.58666L 0.747703,7.58678L 0.747703,0.413038 Z "
HorizontalAlignment="Center"
Margin="0"
VerticalAlignment="Center"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
</s:SurfaceButton>
<!-- Current Color Button -->
<Ellipse Name="CurrentColor"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Row="2"
Grid.Column="3"
Margin="3.5,7,3.5,7"
Fill="Orange"
MouseDown="OnCurrentColorMouseDown"
MouseUp="OnMouseUp"
TouchDown="OnCurrentColorTouchDown"
LostMouseCapture="OnCurrentColorLostMouseCapture"
LostTouchCapture="OnCurrentColorLostTouchCapture"
s:TouchExtensions.TapGesture="OnCurrentColorTap"/>
<!-- Color Wheel -->
<Image Name="ColorWheel"
Source="Resources\ColorWheel.png"
RenderTransformOrigin="0.5, 0.5"
Grid.Row="2"
Grid.Column="3"
Visibility="Hidden"
MouseDown="OnColorWheelMouseDown"
MouseUp="OnMouseUp"
TouchDown="OnColorWheelTouchDown"
LostMouseCapture="OnColorWheelLostMouseCapture"
LostTouchCapture="OnColorWheelLostTouchCapture">
<Image.RenderTransform>
<!-- Transform it so it extends beyond the borders of the grid -->
<ScaleTransform ScaleX="4" ScaleY="4" />
</Image.RenderTransform>
</Image>
</Grid>
</s:ScatterViewItem>
<!-- Photo Pad - Transparent InkCanvas with transparent background overlaid on an image -->
<s:ScatterViewItem x:Name="PhotoPadSVI" Height="320" Width="427" MinWidth="296">
<Grid>
<!-- Row and column definitions to position content and buttons -->
<Grid.RowDefinitions>
<RowDefinition Height="7" />
<RowDefinition />
<RowDefinition Height="52" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44" />
<ColumnDefinition />
<ColumnDefinition Width="44" />
<ColumnDefinition Width="44" />
<ColumnDefinition />
<ColumnDefinition Width="44" />
</Grid.ColumnDefinitions>
<!-- The Ink Canvas -->
<Grid Grid.Column="0" Grid.ColumnSpan="7" Grid.Row="0" Grid.RowSpan="5">
<Image Name="Photo" />
<Viewbox StretchDirection="Both" Stretch="Fill">
<s:SurfaceInkCanvas x:Name="PostcardCanvas" IsHitTestVisible="False" Height="320" Width="426" Background="Transparent" UsesTouchShape="False" />
</Viewbox>
</Grid>
<!-- Clear -->
<s:SurfaceButton Grid.Row="2" Grid.Column="2" Padding="0" Margin="3.5,7,3.5,7" Click="ClearClicked">
<Grid x:Name="X"
Width="38"
Height="38"
Background="Transparent"
VerticalAlignment="Center" >
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="X2"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 0.161144,1.57529L 1.57536,0.161083L 9.00003,7.58576L 16.4247,0.161139L 17.8389,1.57535L 10.4142,8.99997L 17.8388,16.4245L 16.4246,17.8387L 9.00004,10.4142L 1.57542,17.8388L 0.161202,16.4246L 7.58582,8.99997L 0.161144,1.57529 Z "
Margin="0"
Grid.Column="1"
Grid.Row="1" />
</Grid>
</s:SurfaceButton>
<!-- Move/Draw Mode -->
<s:SurfaceButton Grid.Row="2" Grid.Column="3" Padding="0" Margin="3.5,7,3.5,7" Click="InkCanvasOnOffChanged">
<Grid x:Name="MoveButtonImage"
Width="38"
Height="38"
Background="Transparent"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Resize1"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 8.99998,-8.2016e-005L 12,2.99996L 9.99998,2.99996L 9.99998,7.99992L 15,7.99996L 15,6L 18,9L 15,12L 15,9.99996L 9.99998,9.99992L 9.99998,15.0001L 12,15.0001L 8.99996,18.0001L 5.99996,15.0001L 7.99998,15.0001L 7.99998,9.99992L 2.99999,9.99996L 2.99998,12L -1.90735e-005,8.99996L 3.00002,5.99996L 3.00001,7.99996L 7.99998,7.99992L 7.99998,2.99992L 5.99998,2.99992L 8.99998,-8.2016e-005 Z "
HorizontalAlignment="Center"
VerticalAlignment="Center"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
</s:SurfaceButton>
</Grid>
</s:ScatterViewItem>
<!-- Movie Pad - Transparent InkCanvas with transparent background overlaid on a movie -->
<s:ScatterViewItem Height="320"
Width="426"
MinWidth="296"
MaxWidth="853"
Background="{DynamicResource {x:Static s:SurfaceColors.LibraryControlManipulationAreaBackgroundBrushKey}}">
<Grid>
<!-- Row and column definitions to position content and buttons -->
<Grid.RowDefinitions>
<RowDefinition Height="29" />
<RowDefinition />
<RowDefinition Height="52" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="44" />
<ColumnDefinition />
<ColumnDefinition Width="44" />
<ColumnDefinition Width="44" />
<ColumnDefinition Width="44" />
<ColumnDefinition />
<ColumnDefinition Width="44" />
</Grid.ColumnDefinitions>
<!-- The Ink Canvas -->
<Grid Grid.Column="0" Grid.ColumnSpan="7" Grid.Row="1" Grid.RowSpan="1">
<MediaElement x:Name="Movie"
LoadedBehavior="Manual"
UnloadedBehavior="Manual"
MediaEnded="OnMediaEnded" />
<Viewbox StretchDirection="Both" Stretch="Fill">
<!--Events on-->
<s:SurfaceInkCanvas x:Name="MovieCanvas"
Height="240"
Width="427"
Background="Transparent"
IsHitTestVisible="false"
UsesTouchShape="False"
PreviewMouseLeftButtonDown="OnMovieCanvasPreviewLeftMouseDown"
PreviewMouseMove="OnMovieCanvasPreviewMouseMove"
PreviewMouseLeftButtonUp="OnMovieCanvasPreviewLeftMouseUp"
PreviewTouchDown="OnMovieCanvasPreviewTouchDown"
PreviewTouchMove="OnPreviewTouchMoveOrLostCapture"
LostTouchCapture="OnPreviewTouchMoveOrLostCapture">
</s:SurfaceInkCanvas>
</Viewbox>
</Grid>
<!-- Record -->
<s:SurfaceButton x:Name="RecordButton" Grid.Row="2" Grid.Column="2" Padding="0" Margin="3.5,7,3.5,7" VerticalAlignment="Center" Click="OnRecordButtonPressed">
<Grid x:Name="AnotateVideoImage"
Width="38"
Height="38"
VerticalAlignment="Center"
Background="Transparent" >
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Pencil"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Data="F1 M 5.82884,16.4138L 0.172017,17.828L 1.58624,12.1711L 13.5853,0.171997L 17.828,4.41467L 5.82884,16.4138 Z M 2.50753,13.0924L 1.98912,15.1661L 2.83398,16.0109L 4.90755,15.4925L 2.50753,13.0924 Z "
Margin="0"
Grid.Column="1"
Grid.Row="1"/>
</Grid>
</s:SurfaceButton>
<!-- Pause -->
<s:SurfaceButton x:Name="PauseButton" Grid.Row="2" Grid.Column="3" Padding="0" Margin="3.5,7,3.5,7" VerticalAlignment="Center" Click="OnPauseButtonPressed">
<Grid x:Name="Pause"
Height="38"
Width="38"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Grid HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Grid.Column="1" Grid.Row="1">
<Rectangle x:Name="Rectangle_Copy2"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Margin="9,0,0,0"
Height="19"
HorizontalAlignment="Left"
Width="5" />
<Rectangle x:Name="Rectangle_Copy3"
Width="5"
Stretch="Fill"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
HorizontalAlignment="Left"
Margin="0"
Height="19" />
</Grid>
</Grid>
</s:SurfaceButton>
<!-- Play -->
<s:SurfaceButton x:Name="PlayButton" Grid.Row="2" Grid.Column="4" Padding="0" Margin="3.5,7,3.5,7" VerticalAlignment="Center" Click="OnPlayButtonPressed">
<Grid x:Name="Play"
Background="Transparent"
Width="38"
Height="38">
<Grid.RowDefinitions>
<RowDefinition Height="0.25*"/>
<RowDefinition/>
<RowDefinition Height="0.25*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"/>
<ColumnDefinition/>
<ColumnDefinition Width="0.25*"/>
</Grid.ColumnDefinitions>
<Path x:Name="Play1"
Fill="{DynamicResource {x:Static s:SurfaceColors.ButtonForegroundBrushKey}}"
Stretch="Fill"
Margin="0"
VerticalAlignment="Center"
Height="19"
Data="M0,0 L0,18 9,9 z"
Grid.Column="1"
HorizontalAlignment="Center"
Width="10"
Grid.Row="1"/>
</Grid>
</s:SurfaceButton>
</Grid>
</s:ScatterViewItem>
</s:ScatterView>
</Grid>
</s:SurfaceWindow>
C# Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Surface;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;
using Microsoft.Surface.Presentation.Input;
namespace PhotoPaint
{
/// <summary>
/// Interaction logic for Window1.xaml.
/// </summary>
public partial class Window1 : SurfaceWindow
{
/// <summary>
/// The current editing mode for the DrawingPadCanvas.
/// When set, it updates the UI accordingly.
/// </summary>
private SurfaceInkEditingMode CurrentEditingMode
{
get
{
return DrawingPadCanvas.EditingMode;
}
set
{
if (value == SurfaceInkEditingMode.Ink)
{
DrawingPadCanvas.EditingMode = SurfaceInkEditingMode.Ink;
// Update button image to show that we are now in ink mode.
EditModeButton.Content = DrawButtonImage;
}
else
{
DrawingPadCanvas.EditingMode = SurfaceInkEditingMode.EraseByPoint;
// Update button image to show that we are now in erase mode.
EditModeButton.Content = FindResource("EraseButtonImage"); ;
}
}
}
/// <summary>
/// The most recent stroke (used for undo operations).
/// </summary>
private Stroke mostRecentStroke;
/// <summary>
/// A mapping of each stroke to list of point timings in milliseconds.
/// </summary>
private readonly Dictionary<Stroke, List<long>> recordedStrokes = new Dictionary<Stroke, List<long>>();
/// <summary>
/// A copy of the recordedStrokes used for playback.
/// Strokes are removed from this Dictionary as they are played back.
/// </summary>
private Dictionary<Stroke, List<long>> recordedStrokesCopy;
/// <summary>
/// Keeps track of strokes as they are played back.
/// Maps the new stroke (copy) being constructed during playback to the original stroke.
/// </summary>
private readonly Dictionary<Stroke, Stroke> newStrokes = new Dictionary<Stroke, Stroke>();
/// <summary>
/// Whether or not new strokes are being recorded.
/// </summary>
private bool isRecording;
/// <summary>
/// Whether or not strokes are being played back.
/// </summary>
private bool isPlaying;
/// <summary>
/// Whether or not the playback or recording is paused.
/// </summary>
private bool isPaused;
/// <summary>
/// True when end of media has been reached.
/// </summary>
private bool mediaEnded;
/// <summary>
/// Interval timer used to drive recorded stroke playback.
/// </summary>
private DispatcherTimer timer;
/// <summary>
/// Stopwatch used to time strokes for playback when no video is present.
/// </summary>
private Stopwatch stopwatch;
/// <summary>
/// Duration of playback loop (in seconds) when no video is present.
/// </summary>
private const int duration = 12;
/// <summary>
/// Tracks a stroke being created by the mouse.
/// </summary>
private Stroke currentMouseStroke;
/// <summary>
/// Key used to track strokes in a touch device's user data.
/// </summary>
private readonly object strokeKey = new object();
/// <summary>
/// Brushes used for movie buttons
/// </summary>
private static SolidColorBrush buttonHighlightBrush = new SolidColorBrush (Color.FromArgb(0xCC, 0x99, 0x99, 0x99));
private static SolidColorBrush buttonBackgroundBrush = new SolidColorBrush (Color.FromArgb(0xCC, 0xCC, 0xCC, 0xCC));
/// <summary>
/// True when the current color is tapped to open the color wheel
/// </summary>
private bool tappedOpen;
/// <summary>
/// Gets or sets the value of isPaused.
/// </summary>
internal bool IsPaused
{
get { return isPaused; }
set
{
isPaused = value;
if (isPaused)
{
PauseButton.Background = buttonHighlightBrush;
}
else
{
PauseButton.Background = buttonBackgroundBrush;
}
}
}
#region Initalization
/// <summary>
/// Default constructor.
/// </summary>
public Window1()
{
InitializeComponent();
// Add handlers for window availability events
AddWindowAvailabilityHandlers();
// listen for changes to the primary InteractiveSurfaceDevice.
InteractiveSurface.PrimarySurfaceDevice.Changed += OnPrimarySurfaceDeviceChanged;
}
/// <summary>
/// Occurs when the window is about to close.
/// </summary>
/// <param name="e"></param>
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
// Remove handlers for window availability events
RemoveWindowAvailabilityHandlers();
// Stop listening for InteractiveSurfaceDevice changes when the window closes.
InteractiveSurface.PrimarySurfaceDevice.Changed -= OnPrimarySurfaceDeviceChanged;
}
/// <summary>
/// Update the size of photo
/// </summary>
private void OnPrimarySurfaceDeviceChanged(object sender, DeviceChangedEventArgs e)
{
UpdatePhotoSize();
}
/// <summary>
/// Calculate the maximum size of photo based on logical dpi
/// </summary>
private void UpdatePhotoSize()
{
PhotoPadSVI.MaxWidth = Photo.Source.Width / (InteractiveSurface.PrimarySurfaceDevice.LogicalDpiX / 96);
PhotoPadSVI.MaxHeight = Photo.Source.Height / (InteractiveSurface.PrimarySurfaceDevice.LogicalDpiX / 96);
}
/// <summary>
/// Called when the application is finished initalizing
/// </summary>
/// <param name="e"></param>
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
// Load images and video from the public folders.
// These are default OS folders that will always be in these locations
// unless the user has deliberately moved them.
string publicFoldersPath = Environment.GetEnvironmentVariable("public");
SetMoviePadContent(publicFoldersPath + @"\Videos\Sample Videos");
SetPhotoPadContent(publicFoldersPath + @"\Pictures\Sample Pictures");
}
/// <summary>
/// Sets the content for the MovieCanvas.
/// </summary>
/// <param name="publicVideosPath">Path to public videos.</param>
private void SetMoviePadContent(string publicVideosPath)
{
if (Directory.Exists(publicVideosPath))
{
// Use this video if it exists.
string targetVideoPath = publicVideosPath + @"\Wildlife.wmv";
if (File.Exists(targetVideoPath))
{
// Target movie exists, use it.
Movie.Source = new Uri(targetVideoPath);
}
else
{
// Target movie does not exist, use the first WMV found in the directory.
string[] files = Directory.GetFiles(publicVideosPath, "*.wmv");
if (files.Length > 0)
{
Movie.Source = new Uri(files[0]);
}
}
}
if (Movie.Source == null)
{
// If there aren't any movies at all, use a blank canvas.
MovieCanvas.Background = Brushes.White;
stopwatch = new Stopwatch();
}
timer = new DispatcherTimer();
timer.Tick += OnTick;
// Play the movie on startup.
PlayMovie();
// Initial button state.
isPlaying = true;
PlayButton.Background = buttonHighlightBrush;
isRecording = false;
RecordButton.Background = buttonBackgroundBrush;
IsPaused = false;
EnableButtons(true);
}
/// <summary>
/// Sets the content for the PhotoCanvas.
/// </summary>
/// <param name="publicPhotosPath">Path to public photos.</param>
private void SetPhotoPadContent(string publicPhotosPath)
{
if (Directory.Exists(publicPhotosPath))
{
// Use this images if it exists.
string targetPhotoPath = publicPhotosPath + @"\Chrysanthemum.jpg";
if (File.Exists(targetPhotoPath))
{
// Target image exists, use it
Photo.Source = new BitmapImage(new Uri(targetPhotoPath));
}
else
{
// Target image does not exist, use the first JPG found in the directory.
string[] files = Directory.GetFiles(publicPhotosPath, "*.jpg");
if (files.Length > 0)
{
Photo.Source = new BitmapImage(new Uri(files[0]));
}
}
}
if (Photo.Source == null)
{
// If there aren't any images at all, use a blank canvas.
PostcardCanvas.Background = Brushes.White;
}
else
{
UpdatePhotoSize();
}
}
#endregion Initalization
#region InkCanvasEvents
/// <summary>
/// Toggles the edit mode of a SurfaceInkCanvas between EraseByPoint and Ink.
/// </summary>
/// <param name="sender">The object that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void EditModeClicked(object sender, RoutedEventArgs args)
{
SurfaceButton button = (SurfaceButton)sender;
if (CurrentEditingMode == SurfaceInkEditingMode.Ink)
{
CurrentEditingMode = SurfaceInkEditingMode.EraseByPoint;
}
else
{
CurrentEditingMode = SurfaceInkEditingMode.Ink;
}
}
#endregion InkCanvasEvents
#region Drawing Pad Specific Code
/// <summary>
/// Handles the OnStrokeCollected event for SurfaceInkCanvas.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnStrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs args)
{
mostRecentStroke = args.Stroke;
}
/// <summary>
/// Handles the click event for the undo button.
/// </summary>
/// <param name="sender">The button that raised the event.</param>
/// <param name="e">The arguments for the event.</param>
void UndoClicked(object sender, RoutedEventArgs e)
{
if (mostRecentStroke != null)
{
DrawingPadCanvas.Strokes.Remove(mostRecentStroke);
mostRecentStroke = null;
}
}
/// <summary>
/// Handles the TouchDown event for the ColorWheel.
/// </summary>
/// <param name="sender">The color wheel.</param>
/// <param name="args">The arguments for the event.</param>
private void OnColorWheelTouchDown(object sender, TouchEventArgs args)
{
HandleInputDown(sender, args, false);
}
/// <summary>
/// Handles the MouseDown event for the ColorWheel.
/// </summary>
/// <param name="sender">The color wheel.</param>
/// <param name="args">The arguments for the event.</param>
private void OnColorWheelMouseDown(object sender, MouseButtonEventArgs args)
{
HandleInputDown(sender, args, false);
}
/// <summary>
/// Handles the LostTouchCapture event for the ColorWheel.
/// </summary>
/// <param name="sender">The color wheel.</param>
/// <param name="args">The arguments for the event.</param>
private void OnColorWheelLostTouchCapture(object sender, TouchEventArgs args)
{
HandleColorWheelLostCapture(sender, args);
}
/// <summary>
/// Handles the LostMouseCapture event for the ColorWheel.
/// </summary>
/// <param name="sender">The color wheel.</param>
/// <param name="args">The arguments for the event.</param>
private void OnColorWheelLostMouseCapture(object sender, MouseEventArgs args)
{
HandleColorWheelLostCapture(sender, args);
}
private void HandleColorWheelLostCapture(object sender, InputEventArgs args)
{
UIElement element = sender as UIElement;
// If there are input devices captured to the color wheel,
// choose a color based on the position of the last touch device
if (!element.GetAreAnyInputDevicesCaptured())
{
// Select a color if hit, but keep the color wheel open if not
if (ChooseColor(args, true))
{
// If an actual color was chosen, release any capture on the current
// color indicator as the color wheel was already dismissed
CurrentColor.ReleaseAllCaptures();
}
}
}
/// <summary>
/// Handles the Tap gesture event for the current color indicator.
/// </summary>
/// <param name="sender">The current color indicator.</param>
/// <param name="e">The arguments for the event.</param>
private void OnCurrentColorTap(object sender, TouchEventArgs e)
{
// This event will be followed by a LostTouchCapture event.
// Flag that it was tapped so that method can ensure the
// color wheel stays open.
tappedOpen = true;
}
/// <summary>
/// Handles the LostTouchCapture event for the current color indicator.
/// </summary>
/// <param name="sender">The current color indicator.</param>
/// <param name="args">The arguments for the event.</param>
private void OnCurrentColorLostTouchCapture(object sender, TouchEventArgs args)
{
// Select a color if hit, based on the position of the only touch device
// that just lost capture on the CurrentColor indicator and always dismiss
// the color wheel
ChooseColor(args, tappedOpen);
tappedOpen = false;
}
/// <summary>
/// Handles the LostMouseCapture event for the current color indicator.
/// </summary>
/// <param name="sender">The current color indicator.</param>
/// <param name="args">The arguments for the event.</param>
private void OnCurrentColorLostMouseCapture(object sender, MouseEventArgs args)
{
// Select a color if hit, based on the position of the only touch device
// that just lost capture on the CurrentColor indicator and always dismiss
// the color wheel
ChooseColor(args, false);
}
/// <summary>
/// Handles the MouseUp event for the current color indicator or color wheel.
/// </summary>
/// <param name="sender">The current color indicator or color wheel.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMouseUp(object sender, MouseButtonEventArgs args)
{
// If the mouse was already captured to the sender, release it
IInputElement element = sender as IInputElement;
if (args.Device.GetCaptured() == element)
{
element.ReleaseMouseCapture();
}
}
/// <summary>
/// Select a color based on the postion of args.TouchDevice if hit.
/// </summary>
/// <param name="args">The arguments for the input event.</param>
/// <param name="closeOnlyOnHit">Indicates if the ColorWheel should
/// be kept open when an actual color is chosen.</param>
/// <returns> true if a color was actually chosen.</returns>
private bool ChooseColor(InputEventArgs args, bool closeOnlyOnHit)
{
// If the color wheel is not visible, bail out
if (ColorWheel.Visibility == Visibility.Hidden)
{
return false;
}
// Set the color on the CurrentColor indicator and on the SurfaceInkCanvas
Color color = GetPixelColor(args.Device);
// Black means the user touched the transparent part of the wheel. In that
// case, leave the color set to its current value
bool hit = color != Colors.Black;
// close the colorwheel if caller always requests or only if a
// color is actually chosen.
bool close = !closeOnlyOnHit || hit;
if (hit)
{
DrawingPadCanvas.DefaultDrawingAttributes.Color = color;
CurrentColor.Fill = new SolidColorBrush(color);
}
if (close)
{
CurrentEditingMode = SurfaceInkEditingMode.Ink;
// Replace the color wheel with the current color button
ColorWheel.Visibility = Visibility.Hidden;
}
args.Handled = true;
return hit;
}
/// <summary>
/// Handles the TouchtDownEvent for the current color indicator.
/// </summary>
/// <param name="sender">The current color indicator that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnCurrentColorTouchDown(object sender, TouchEventArgs args)
{
HandleInputDown(sender, args, true);
}
/// <summary>
/// Handles the MouseDownEvent for the current color indicator.
/// </summary>
/// <param name="sender">The current color indicator that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnCurrentColorMouseDown(object sender, MouseButtonEventArgs args)
{
HandleInputDown(sender, args, true);
}
private void HandleInputDown(object sender, InputEventArgs args, bool makeVisible)
{
// Capture the touch device and handle the event
IInputElement element = sender as IInputElement;
if (element != null && args.Device.Capture(element))
{
args.Handled = true;
}
if (makeVisible)
{
// Overlay the current color button with the color wheel
ColorWheel.Visibility = Visibility.Visible;
}
}
/// <summary>
/// Gets the color of a specific pixel.
/// </summary>
/// <param name="pt">The point from which to get a color.</param>
/// <returns>The color of the point.</returns>
private System.Windows.Media.Color GetPixelColor(InputDevice inputDevice)
{
// Translate the input point to bitmap coordinates
double transformFactor = ColorWheel.Source.Width / ColorWheel.ActualWidth;
Point inputPoint = inputDevice.GetPosition(ColorWheel);
Point bitmapPoint = new Point(inputPoint.X * transformFactor, inputPoint.Y * transformFactor);
// The point is outside the color wheel. Return black.
if (bitmapPoint.X < 0 || bitmapPoint.X >= ColorWheel.Source.Width ||
bitmapPoint.Y < 0 || bitmapPoint.Y >= ColorWheel.Source.Height)
{
return Colors.Black;
}
// The point is inside the color wheel. Find the color at the point.
CroppedBitmap cb = new CroppedBitmap(ColorWheel.Source as BitmapSource, new Int32Rect((int)bitmapPoint.X, (int)bitmapPoint.Y, 1, 1));
byte[] pixels = new byte[4];
cb.CopyPixels(pixels, 4, 0);
return Color.FromRgb(pixels[2], pixels[1], pixels[0]);
}
#endregion Drawing Pad Specific Code
#region Photo Pad Specific Code
/// <summary>
/// Handles the click event for the clear button.
/// </summary>
/// <param name="sender">The button that reaised the event.</param>
/// <param name="e">The arguments for the event.</param>
void ClearClicked(object sender, RoutedEventArgs e)
{
PostcardCanvas.Strokes.Clear();
}
/// <summary>
/// Handles the click event for the Move/Draw mode button on the PhotoPad.
/// </summary>
/// <param name="sender">The button that raised the event.</param>
/// <param name="e">The arguments for the event.</param>
void InkCanvasOnOffChanged(object sender, RoutedEventArgs e)
{
SurfaceButton button = (SurfaceButton) sender;
if (PostcardCanvas.IsHitTestVisible)
{
// Prevent the SurfaceinkCanvas from processing input
PostcardCanvas.IsHitTestVisible = false;
// Load the new button image
button.Content = MoveButtonImage;
}
else
{
// Let the SurfaceinkCanvas start processing input
PostcardCanvas.IsHitTestVisible = true;
// Load the new button image
button.Content = FindResource("EditButtonImage");
}
}
#endregion Photo Pad Specific Code
#region Movie Pad Specific Code
#region Input Event Handlers
// Remarks:
//
// We use the preview events because the normal events are consumed by
// the MovieCanvas.
//
// These events are used to create a stroke that looks like the stroke
// being added to the MovieCanvas. The actual stroke is not available
// until it is completed. We use these events to record the stroke and
// timestamp data so we can manully recreate the stroke during playback.
/// <summary>
/// Handles the PreviewTouchDown event for the MovieCanvas.
/// Begins recording a new stroke.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMovieCanvasPreviewTouchDown(object sender, TouchEventArgs args)
{
// If isRecord is set to true, record the stroke for playback later.
if (isRecording && MovieCanvas.CaptureTouch(args.TouchDevice))
{
SurfaceInkCanvas canvas = (SurfaceInkCanvas)sender;
System.Windows.Point point = args.TouchDevice.GetPosition(canvas);
StylusPointCollection points = new StylusPointCollection();
points.Add(new StylusPoint(point.X, point.Y));
// Cannot create a stroke without at least one point in the StylusPointCollection
Stroke stroke = new Stroke(points);
stroke.DrawingAttributes = canvas.DefaultDrawingAttributes.Clone();
if (MovieCanvas.UsesTouchShape)
{
stroke.DrawingAttributes.StylusTip = StylusTip.Ellipse;
Ellipse touchEllipse = args.TouchDevice.GetEllipse(MovieCanvas);
stroke.DrawingAttributes.Height = touchEllipse.Height;
stroke.DrawingAttributes.Width = touchEllipse.Width;
Matrix rotate = Matrix.Identity;
rotate.Rotate(args.TouchDevice.GetOrientation(MovieCanvas));
stroke.DrawingAttributes.StylusTipTransform = rotate;
}
recordedStrokes.Add(stroke, new List<long>());
recordedStrokes[stroke].Add(CurrentPosition());
// Associate the new stroke with this touch device
args.TouchDevice.SetUserData(strokeKey, stroke);
}
}
/// <summary>
/// Handles PreviewTouchMove and LostTouchCapture events for the MovieCanvas.
/// Adds a point to the stroke associated with the touch device.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnPreviewTouchMoveOrLostCapture(object sender, TouchEventArgs args)
{
if (isRecording)
{
// Retrieve the stroke assocatiated with this touch device
Stroke stroke = args.TouchDevice.GetUserData(strokeKey) as Stroke;
if (stroke != null)
{
SurfaceInkCanvas canvas = (SurfaceInkCanvas) sender;
System.Windows.Point position = args.TouchDevice.GetPosition(canvas);
AddPointToStroke(stroke, position.X, position.Y);
}
}
}
/// <summary>
/// Handles the PreviewLeftMouseDown event for the MovieCanvas.
/// Begins a new currentMouseStroke.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMovieCanvasPreviewLeftMouseDown(object sender, MouseButtonEventArgs args)
{
if (isRecording)
{
SurfaceInkCanvas canvas = (SurfaceInkCanvas)sender;
System.Windows.Point point = args.MouseDevice.GetPosition(MovieCanvas);
StylusPointCollection points = new StylusPointCollection();
points.Add(new StylusPoint(point.X, point.Y));
currentMouseStroke = new Stroke(points);
currentMouseStroke.DrawingAttributes = canvas.DefaultDrawingAttributes.Clone();
recordedStrokes.Add(currentMouseStroke, new List<long>());
recordedStrokes[currentMouseStroke].Add(CurrentPosition());
}
}
/// <summary>
/// Handles the PreviewMouseMove event for the MovieCanvas.
/// Adds point to currentMouseStroke and record timing data.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMovieCanvasPreviewMouseMove(object sender, MouseEventArgs args)
{
if (isRecording && currentMouseStroke != null)
{
System.Windows.Point position = args.MouseDevice.GetPosition(MovieCanvas);
AddPointToStroke(currentMouseStroke, position.X, position.Y);
}
}
/// <summary>
/// Handles the PreviewLeftMouseUp event for the MovieCanvas.
/// Ends the currentMouseStroke.
/// </summary>
/// <param name="sender">The SurfaceInkCanvas that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMovieCanvasPreviewLeftMouseUp(object sender, MouseButtonEventArgs args)
{
if (isRecording && currentMouseStroke != null)
{
System.Windows.Point position = args.MouseDevice.GetPosition(MovieCanvas);
AddPointToStroke(currentMouseStroke, position.X, position.Y);
}
currentMouseStroke = null;
}
/// <summary>
/// Adds a point to a Stroke and records the time the point was added.
/// </summary>
/// <param name="stroke">The stroke to modify</param>
/// <param name="positionX">The X coordinate of the point to add</param>
/// <param name="positionY">the Y coordinate of the point to add</param>
private void AddPointToStroke(Stroke stroke, double positionX, double positionY)
{
stroke.StylusPoints.Add(new StylusPoint(positionX, positionY));
if (recordedStrokes.ContainsKey(stroke))
{
recordedStrokes[stroke].Add(CurrentPosition());
}
}
#endregion
#region Button Event Handlers
/// <summary>
/// Handles the click event for the record button.
/// Resumes the current recording, or starts a new recording from the
/// beginning of our media.
/// </summary>
/// <param name="sender">The button that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnRecordButtonPressed(object sender, RoutedEventArgs args)
{
if (IsPaused && isRecording)
{
// Just Keep doing what we were doing.
PlayMovie();
return;
}
// Stop stroke playback
isPlaying = false;
PlayButton.Background = buttonBackgroundBrush;
// Begin new recording
MovieCanvas.Strokes.Clear();
recordedStrokes.Clear();
isRecording = true;
RecordButton.Background = buttonHighlightBrush;
// Allow user to draw on the SurfaceInkCanvas.
MovieCanvas.IsHitTestVisible = true;
RestartMovie();
}
/// <summary>
/// Handles the click event for the play button.
/// Resumes the current playback, or start a new playback from the
/// beginning of our media.
/// </summary>
/// <param name="sender">The button that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnPlayButtonPressed(object sender, RoutedEventArgs args)
{
if (IsPaused && isPlaying)
{
// Just Keep doing what we were doing.
PlayMovie();
return;
}
// Stop recording
isRecording = false;
RecordButton.Background = buttonBackgroundBrush;
MovieCanvas.IsHitTestVisible = false;
ResetPlayback();
isPlaying = true;
PlayButton.Background = buttonHighlightBrush;
RestartMovie();
}
/// <summary>
/// Handles the click event for the pause button.
/// Resumes the current recording or playback. If at end of media,
/// then start a new playback.
/// </summary>
/// <param name="sender">The button that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnPauseButtonPressed(object sender, RoutedEventArgs args)
{
if (IsPaused)
{
if (mediaEnded)
{
// If at the end media, treat hitting pause like hitting play.
OnPlayButtonPressed(sender, args);
}
else
{
PlayMovie();
}
}
else
{
PauseMovie();
}
}
#endregion
/// <summary>
/// Handles the MediaEnded event for the MovieCanvas video.
/// </summary>
/// <param name="sender">The MediaElement that raised the event.</param>
/// <param name="args">The arguments for the event.</param>
private void OnMediaEnded(object sender, RoutedEventArgs args)
{
mediaEnded = true;
Reset();
}
/// <summary>
/// Resets all buttons on MovieCanvas to initial state.
/// </summary>
private void Reset()
{
MovieCanvas.IsHitTestVisible = false;
PauseMovie();
PauseButton.Opacity = 1.0;
isPlaying = false;
PlayButton.Background = buttonBackgroundBrush;
PlayButton.Opacity = 1.0;
isRecording = false;
RecordButton.Background = buttonBackgroundBrush;
RecordButton.Opacity = 1.0;
EnableButtons(true);
}
/// <summary>
/// Handles the Tick event from the DispatcherTimer.
/// On each tick determines what strokes need to be added to the canvas.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnTick(object sender, EventArgs e)
{
timer.Stop();
try
{
if (IsPaused) { return; }
// If there is no media, determine if the record/playback loop should end.
if (stopwatch != null && stopwatch.Elapsed.Seconds >= duration)
{
OnMediaEnded(null, null);
return;
}
if (recordedStrokesCopy == null || recordedStrokesCopy.Count < 1)
{
// There are no strokes to play back.
return;
}
// Determine what strokes/points needed to be added to the MovieCanvas.
if (isPlaying && !IsPaused)
{
// Get the current time in the playback loop.
long elapsed = CurrentPosition();
foreach (Stroke copy in newStrokes.Keys)
{
Stroke original = newStrokes[copy];
if (!recordedStrokesCopy.ContainsKey(original))
{
// The complete stroke has already been added to the canvas.
continue;
}
List<long> dueTime = recordedStrokesCopy[original];
// See if the stroke is already added.
if (MovieCanvas.Strokes.Contains(copy))
{
// Stroke is already added. Add a new point to the stroke.
int added = copy.StylusPoints.Count;
if (added < original.StylusPoints.Count)
{
// There are more points to add.
if (dueTime.Count > added && elapsed >= dueTime[added])
{
// It's time to add this point.
StylusPoint point = original.StylusPoints[copy.StylusPoints.Count];
copy.StylusPoints.Add(point);
if (copy.StylusPoints.Count == original.StylusPoints.Count)
{
// We've added all the points for this stroke.
recordedStrokesCopy.Remove(original);
}
}
}
}
else
{
// Stroke has not been added yet. See if it's time to add it.
// We already added the first point when we created the strokes.
if (dueTime.Count > 0 && elapsed >= dueTime[0])
{
MovieCanvas.Strokes.Add(copy);
}
}
}
}
}
finally
{
timer.Start();
}
}
/// <summary>
/// Resets MoviePad state to begin stroke playback.
/// </summary>
private void ResetPlayback()
{
PauseMovie();
ResetPosition();;
MovieCanvas.Strokes.Clear();
// Make a copy of the recorded strokes dictionary so its contents can be modified
// without changing the original dictionary
recordedStrokesCopy = new Dictionary<Stroke, List<long>>(recordedStrokes);
// Make a dictionary of all the strokes the user recorded mapped to copies of those strokes.
//
// These copies will:
// - Only have one point in their strokes collection
// - Have the same DrawingAttributes as their mapped stroke
// - Be added to the SurfaceInkCanvaas instead of the original stroke
// - Have additional points added as the movie plays
newStrokes.Clear();
// Copy the recorded strokes into a new distionary, but only copy the first point
// of each stroke so the stroke can grow as the movie plays.
foreach (Stroke original in recordedStrokesCopy.Keys)
{
StylusPointCollection points = new StylusPointCollection();
points.Add(original.StylusPoints[0]);
Stroke copy = new Stroke(points);
copy.DrawingAttributes = original.DrawingAttributes;
newStrokes.Add(copy, original);
}
}
/// <summary>
/// Returns the current position in the playback loop.
/// </summary>
/// <returns></returns>
private long CurrentPosition()
{
if (stopwatch != null)
{
return stopwatch.ElapsedMilliseconds;
}
else
{
return (long) Movie.Position.TotalMilliseconds;
}
}
/// <summary>
/// Resets the current position to the start of the playback loop.
/// </summary>
private void ResetPosition()
{
if (stopwatch != null)
{
stopwatch.Reset();
}
else
{
Movie.Position = TimeSpan.Zero;
}
}
/// <summary>
/// Starts the playback from the beginning.
/// </summary>
private void RestartMovie()
{
ResetPosition();
PlayMovie();
mediaEnded = false;
}
/// <summary>
/// Resumes the playback from current position.
/// </summary>
/// <returns></returns>
private void PlayMovie()
{
timer.Start();
if (stopwatch != null)
{
stopwatch.Start();
}
else
{
Movie.Play();
}
IsPaused = false;
}
/// <summary>
/// Pauses the media playback.
/// </summary>
private void PauseMovie()
{
if (IsPaused) return;
timer.Stop();
if (stopwatch != null)
{
stopwatch.Stop();
}
else
{
Movie.Pause();
}
IsPaused = true;
}
/// <summary>
/// Stops the media playback and resets the MoviePad.
/// </summary>
private void StopMovie()
{
timer.Stop();
if (stopwatch != null)
{
stopwatch.Stop();
}
else
{
Movie.Stop();
}
Reset();
}
/// <summary>
/// Enables or Diables MoviePad buttons according to the isEnabled parameter.
/// </summary>
/// <param name="isEnabled">Boolean indicating if the buttons are enabled or not.</param>
private void EnableButtons(bool isEnabled)
{
PlayButton.IsEnabled = isEnabled;
RecordButton.IsEnabled = isEnabled;
PauseButton.IsEnabled = isEnabled;
}
#endregion Movie Pad Specific Code
/// <summary>
/// Loads an image.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private static Image LoadImageFromPath(string path)
{
ImageSourceConverter converter = new ImageSourceConverter();
Image image = new Image();
image.Source = (ImageSource)converter.ConvertFromString(path);
return image;
}
/// <summary>
/// Adds handlers for window availability events.
/// </summary>
private void AddWindowAvailabilityHandlers()
{
// Subscribe to surface window availability events
ApplicationServices.WindowInteractive += OnWindowInteractive;
ApplicationServices.WindowNoninteractive += OnWindowNoninteractive;
ApplicationServices.WindowUnavailable += OnWindowUnavailable;
}
/// <summary>
/// Removes handlers for window availability events.
/// </summary>
private void RemoveWindowAvailabilityHandlers()
{
// Unsubscribe from surface window availability events
ApplicationServices.WindowInteractive -= OnWindowInteractive;
ApplicationServices.WindowNoninteractive -= OnWindowNoninteractive;
ApplicationServices.WindowUnavailable -= OnWindowUnavailable;
}
/// <summary>
/// This is called when the user can interact with the application's window.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnWindowInteractive(object sender, EventArgs e)
{
// Enable audio for our movie.
Movie.IsMuted = false;
}
/// <summary>
/// This is called when the user can see but not interact with the application's window.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnWindowNoninteractive(object sender, EventArgs e)
{
// Disable audio for our movie.
Movie.IsMuted = true;
}
/// <summary>
/// This is called when the application's window is not visible or interactive.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnWindowUnavailable(object sender, EventArgs e)
{
// If our movie is currently playing, stop it.
StopMovie();
}
}
}
转载时须注明本文的详细链接,否则作者将保留追究其法律责任。
出处:http://www.cnblogs.com/flute-di/
推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架