Collect Ink
The Windows Presentation Foundation platform collects digital ink as a core part of its functionality. This topic discusses methods for collection of ink in Windows Presentation Foundation (WPF).
To use the following examples, you must first install Visual Studio and the Windows SDK. You should also understand how to write applications for the WPF. For more information about getting started with WPF, see Walkthrough: My first WPF desktop application.
The System.Windows.Controls.InkCanvas element provides the easiest way to collect ink in WPF. Use an InkCanvas element to receive and display ink input. You commonly input ink through the use of a stylus, which interacts with a digitizer to produce ink strokes. In addition, a mouse can be used in place of a stylus. The created strokes are represented as Stroke objects, and they can be manipulated both programmatically and by user input. The InkCanvas enables users to select, modify, or delete an existing Stroke.
By using XAML, you can set up ink collection as easily as adding an InkCanvas element to your tree. The following example adds an InkCanvas to a default WPF project created in Visual Studio:
<Grid>
<InkCanvas/>
</Grid>
The InkCanvas element can also contain child elements, making it possible to add ink annotation capabilities to almost any type of XAML element. For example, to add inking capabilities to a text element, simply make it a child of an InkCanvas:
<InkCanvas>
<TextBlock>Show text here.</TextBlock>
</InkCanvas>
Adding support for marking up an image with ink is just as easy:
<InkCanvas>
<Image Source="myPicture.jpg"/>
</InkCanvas>
The InkCanvas provides support for various input modes through its EditingMode property.
The InkCanvas provides support for many ink editing operations. For example, InkCanvas supports back-of-pen erase, and no additional code is needed to add the functionality to the element.
Setting selection mode is as simple as setting the InkCanvasEditingMode property to Select.
The following code sets the editing mode based on the value of a CheckBox:
// Set the selection mode based on a checkbox
if ((bool)cbSelectionMode.IsChecked)
{
theInkCanvas.EditingMode = InkCanvasEditingMode.Select;
}
else
{
theInkCanvas.EditingMode = InkCanvasEditingMode.Ink;
}
' Set the selection mode based on a checkbox
If CBool(cbSelectionMode.IsChecked) Then
theInkCanvas.EditingMode = InkCanvasEditingMode.Select
Else
theInkCanvas.EditingMode = InkCanvasEditingMode.Ink
End If
Use the DrawingAttributes property to change the appearance of ink strokes. For instance, the Color member of DrawingAttributes sets the color of the rendered Stroke.
The following example changes the color of the selected strokes to red:
// Get the selected strokes from the InkCanvas
StrokeCollection selection = theInkCanvas.GetSelectedStrokes();
// Check to see if any strokes are actually selected
if (selection.Count > 0)
{
// Change the color of each stroke in the collection to red
foreach (System.Windows.Ink.Stroke stroke in selection)
{
stroke.DrawingAttributes.Color = System.Windows.Media.Colors.Red;
}
}
' Get the selected strokes from the InkCanvas
Dim selection As StrokeCollection = theInkCanvas.GetSelectedStrokes()
' Check to see if any strokes are actually selected
If selection.Count > 0 Then
' Change the color of each stroke in the collection to red
Dim stroke As System.Windows.Ink.Stroke
For Each stroke In selection
stroke.DrawingAttributes.Color = System.Windows.Media.Colors.Red
Next stroke
End If
The DefaultDrawingAttributes property provides access to properties such as the height, width, and color of the strokes to be created in an InkCanvas. Once you change the DefaultDrawingAttributes, all future strokes entered into the InkCanvas are rendered with the new property values.
In addition to modifying the DefaultDrawingAttributes in the code-behind file, you can use XAML syntax for specifying DefaultDrawingAttributes properties.
The next example demonstrates how to set the Color property. To use this code, create a new WPF project called "HelloInkCanvas" in Visual Studio. Replace the code in the MainWindow.xaml file with the following code:
<Window x:Class="HelloInkCanvas.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Ink="clr-namespace:System.Windows.Ink;assembly=PresentationCore"
Title="Hello, InkCanvas!" Height="300" Width="300"
>
<Grid>
<InkCanvas Name="inkCanvas1" Background="Ivory">
<InkCanvas.DefaultDrawingAttributes>
<Ink:DrawingAttributes xmlns:ink="system-windows-ink" Color="Red" Width="5" />
</InkCanvas.DefaultDrawingAttributes>
</InkCanvas>
<!-- This stack panel of buttons is a sibling to InkCanvas (not a child) but overlapping it,
higher in z-order, so that ink is collected and rendered behind -->
<StackPanel Name="buttonBar" VerticalAlignment="Top" Height="26" Orientation="Horizontal" Margin="5">
<Button Click="Ink">Ink</Button>
<Button Click="Highlight">Highlight</Button>
<Button Click="EraseStroke">EraseStroke</Button>
<Button Click="Select">Select</Button>
</StackPanel>
</Grid>
</Window>
Next, add the following button event handlers to the code behind file, inside the MainWindow class:
// Set the EditingMode to ink input.
private void Ink(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Ink;
// Set the DefaultDrawingAttributes for a red pen.
inkCanvas1.DefaultDrawingAttributes.Color = Colors.Red;
inkCanvas1.DefaultDrawingAttributes.IsHighlighter = false;
inkCanvas1.DefaultDrawingAttributes.Height = 2;
}
// Set the EditingMode to highlighter input.
private void Highlight(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Ink;
// Set the DefaultDrawingAttributes for a highlighter pen.
inkCanvas1.DefaultDrawingAttributes.Color = Colors.Yellow;
inkCanvas1.DefaultDrawingAttributes.IsHighlighter = true;
inkCanvas1.DefaultDrawingAttributes.Height = 25;
}
// Set the EditingMode to erase by stroke.
private void EraseStroke(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.EraseByStroke;
}
// Set the EditingMode to selection.
private void Select(object sender, RoutedEventArgs e)
{
inkCanvas1.EditingMode = InkCanvasEditingMode.Select;
}
After copying this code, press F5 in Visual Studio to run the program in the debugger.
Notice how the StackPanel places the buttons on top of the InkCanvas. If you try to ink over the top of the buttons, the InkCanvas collects and renders the ink behind the buttons. This is because the buttons are siblings of the InkCanvas as opposed to children. Also, the buttons are higher in the z-order, so the ink is rendered behind them.
.NET Desktop feedback feedback
.NET Desktop feedback is an open source project. Select a link to provide feedback: