The sample for this section is a simple sketch page that allows the user to draw a picture, undo and redo sketch lines, and clear the page using an application bar menu item (see Figure 7.4). The code presented in this section elaborates on the previous example and takes a more MVVM-centric approach.
The code for this sample is located in the InkPresenterView
page and the InkPresenterViewModel
class in the downloadable sample code.
An InkPresenter
in the view is bound to the viewmodel’s StrokeCollection
. As the user interacts with the view, viewmodel commands populate the StrokeCollection
with Stroke
objects.
Each command is instantiated in the viewmodel’s constructor. When executed, the beginStrokeCommand
creates a new Stroke
representing the beginning of a line drawn by the user. As the user moves a finger across the InkPresenter
, the setStrokePointCommand
is executed, which adds a new StylusPoint
to the list of points for the current Stroke
. Finally, when the user takes his finger off the display, the endStrokeCommand
is executed setting the current Stroke
to null (see Listing 7.2).
The viewmodel maintains a Stack
of Strokes
, called undoneStrokes
, which contains strokes that have been undone by the user. The undoCommand
pushes the last Stroke
in the StrokeCollection
onto undoneStrokes
and then removes it from the StrokesCollection
. Conversely, the redoCommand
pops the top Stroke
from undoneStrokes
and places it back in the StrokesCollection
.
public InkPresenterViewModel() : base("InkPresenter")
{
beginStrokeCommand = new DelegateCommand<Point>(
point =>
{
stroke = new Stroke();
stroke.StylusPoints.Add(ConvertToStylusPoint(point));
stroke.DrawingAttributes.Color = stylusColor;
strokes.Add(stroke);
});
setStrokePointCommand = new DelegateCommand<Point>(
point =>
{
if (stroke != null)
{
stroke.StylusPoints.Add(ConvertToStylusPoint(point));
}
});
endStrokeCommand = new DelegateCommand(obj => stroke = null);
clearCommand = new DelegateCommand(obj => strokes.Clear());
undoCommand = new DelegateCommand(
delegate
{
if (strokes.Count > 0)
{
undoneStrokes.Push(strokes.Last());
strokes.RemoveAt(strokes.Count - 1);
}
});
redoCommand = new DelegateCommand(
delegate
{
if (undoneStrokes.Count > 0)
{
strokes.Add(undoneStrokes.Pop());
}
});
}
The BeginStrokeCommand
, SetStrokePointCommand
, and EndStrokeCommand
are executed when the InkPresenters
element’s MouseLeftButtonDown
, MouseMove
, and MouseLeftButtonUp
events are raised, respectively (see Listing 7.3).
public partial class InkPresenterView : PhoneApplicationPage
{
public InkPresenterView()
{
InitializeComponent();
DataContext = new InkPresenterViewModel();
}
InkPresenterViewModel ViewModel
{
get
{
return (InkPresenterViewModel)DataContext;
}
}
void InkPresenter_MouseMove(object sender, MouseEventArgs e)
{
InkPresenter inkPresenter = (InkPresenter)sender;
ViewModel.SetStrokePointCommand.Execute(e.GetPosition(inkPresenter));
}
void InkPresenter_MouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
{
InkPresenter inkPresenter = (InkPresenter)sender;
ViewModel.BeginStrokeCommand.Execute(e.GetPosition(inkPresenter));
}
void InkPresenter_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ViewModel.EndStrokeCommand.Execute(null);
}
}
The three commands UndoCommand
, RedoCommand
, and ClearCommand
are executed via the custom ApplicationBar
wrapper, named AppBar
, in the view. The AppBar
is discussed further in Chapter 8, “Taming the Application Bar.”
<u:AppBar IsEnabled="True" IsVisible="True" IsMenuEnabled="True">
<u:AppBarIconButton
Command="{Binding UndoCommand}"
Text="Undo"
IconUri="/ControlExamples/Images/AppBarArrowUndo.png" />
<u:AppBarIconButton
Command="{Binding RedoCommand}"
Text="Redo"
IconUri="/ControlExamples/Images/AppBarArrowRedo.png" />
<u:AppBar.MenuItems>
<u:AppBarMenuItem
Command="{Binding ClearCommand}"
Text="Clear" />
</u:AppBar.MenuItems>
</u:AppBar>
When the Undo or Redo buttons are pressed, the associated viewmodel command is executed. In addition, when the user taps the Clear button in the application bar menu the ClearCommand
is executed, removing all items from the StrokeCollection
in the viewmodel.
18.227.134.232