The content area of Jot is tiny but significant:
Example 1. Silverlight Project: Jot File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <InkPresenter Name="inkPresenter" /> </Grid>
|
As the name suggests, the InkPresenter renders virtual ink that comes from stylus or touch input. The InkPresenter
doesn’t collect that ink on its own. That’s your responsibility. (And
Silverlight has no built-in handwriting recognition, although there’s
nothing to prevent you from adding your own.)
The code-behind file requires a using directive for the System.Windows.Ink namespace and defines just two private fields:
Example 2. Silverlight Project: Jot File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage { JotAppSettings appSettings = (Application.Current as App).AppSettings; Dictionary<int, Stroke> activeStrokes = new Dictionary<int, Stroke>();
public MainPage() { InitializeComponent();
inkPresenter.Strokes = appSettings.StrokeCollections[appSettings.PageNumber]; inkPresenter.Background = new SolidColorBrush(appSettings.Background); . . . TitleAndAppbarUpdate();
Touch.FrameReported += OnTouchFrameReported; } . . . }
|
The first field provides convenient access to the application settings exposed by the App class. The second is for maintaining multi-touch data. The constructor initializes both the Strokes and Background property of the InkPresenter from application data, and concludes by setting a handler for the low-level Touch.FrameReported event. (I’ll discuss the TitleAndAppbarUpdate method a little later.)
I chose to use low-level touch
input because the program isn’t manipulating anything. It’s only
interested in getting points corresponding to finger movement. With Touch.FrameReported, the program can get input from multiple fingers at once, but of course, it’s a little tricky in actual practice.
You’ll recall that with Touch.FrameReported
event, each finger is identified with an integer ID from the moment it
touches the screen to the time it lifts off. In this program, the
activity of that finger generates a new Stroke for the Strokes property of InkPresenter. Keeping a finger’s ID associated with its Stroke is the purpose of that Dictionary named activeStrokes:
Dictionary<int, Stroke> activeStrokes = new Dictionary<int, Stroke>();
Here’s the OnTouchFrameReported handler:
Example 3. Silverlight Project: Jot File: MainPage.xaml.cs (excerpt)
void OnTouchFrameReported(object sender, TouchFrameEventArgs args) { TouchPoint primaryTouchPoint = args.GetPrimaryTouchPoint(null);
if (primaryTouchPoint != null && primaryTouchPoint.Action == TouchAction.Down) args.SuspendMousePromotionUntilTouchUp();
TouchPointCollection touchPoints = args.GetTouchPoints(inkPresenter);
foreach (TouchPoint touchPoint in touchPoints) { Point pt = touchPoint.Position; int id = touchPoint.TouchDevice.Id;
switch (touchPoint.Action) { case TouchAction.Down: Stroke stroke = new Stroke(); stroke.DrawingAttributes.Color = appSettings.Foreground; stroke.DrawingAttributes.Height = appSettings.StrokeWidth; stroke.DrawingAttributes.Width = appSettings.StrokeWidth; stroke.StylusPoints.Add(new StylusPoint(pt.X, pt.Y));
inkPresenter.Strokes.Add(stroke); activeStrokes.Add(id, stroke); break;
case TouchAction.Move: activeStrokes[id].StylusPoints.Add(new StylusPoint(pt.X, pt.Y)); break;
case TouchAction.Up: activeStrokes[id].StylusPoints.Add(new StylusPoint(pt.X, pt.Y)); activeStrokes.Remove(id);
TitleAndAppbarUpdate(); break; } } }
|
When the finger first touches the screen (signaled by an Action property of TouchAction.Down), the method creates a new Stroke object. This is added to the Strokes collection of the InkPresenter, and it is re-rendered by InkPresenter with each new point added to it. That Stroke object is also stored in the activeStrokesStroke to be built up with each TouchAction.Move event. The entry is removed from the dictionary when the finger leaves the screen. dictionary along with the ID. That allows the