#490 – Using the InkCanvas to Recognize Gestures, part II

With the EditingMode of an InkCanvas set to GestureOnly or to InkAndGesture, the InkCanvas will attempt to recognize any gestures drawn using a mouse or a stylus.

You can handle the Gesture event of an InkCanvas and then call the GetGestureRecognitionResults to get a list of candidate gestures that the InkCanvas thinks that you drew.  In the example below, we get this list of gestures and dump them out to a debug window.

        private void ink_Gesture(object sender, InkCanvasGestureEventArgs e)
        {
            ReadOnlyCollection<GestureRecognitionResult> gestures = e.GetGestureRecognitionResults();

            foreach (GestureRecognitionResult gest in gestures)
            {
                Trace.WriteLine(string.Format("Gesture: {0}, Confidence: {1}", gest.ApplicationGesture, gest.RecognitionConfidence));
            }
        }

Below are some example gestures, followed by the list of GestureRecognitionResult objects. Each has a Confidence property that indicates how confident .NET is of the suggested result.

#489 – Using the InkCanvas to Recognize Gestures, part I

You can set the EditingMode of an InkCanvas to recognize gestures, rather than to let the users draw strokes onto the surface of the InkCanvas.  If you set the EditingMode to GestureOnly, the user cannot draw on the control, but can use the mouse or stylus to draw a gesture, which the InkCanvas will try to recognize.

In this mode, anything that you draw will show up as a stroke while you’re drawing it, but will then disappear as soon as you lift the mouse or stylus.

Drawing:

Done drawing:

As soon as you finish drawing, the InkCanvas will try to recognize what you drew.  It will fire the Gesture event, where you can ask it what gestures it thinks it recognized.

Gestures that the InkCanvas can recognize are listed in the System.Windows.Ink.ApplicationGesture enumeration.  These include things like: circles, squares, checks, and flicks in different directions.

#488 – You Can Change Drawing Attributes of Existing Strokes in an InkCanvas

You can change the drawing attributes for new strokes added to an InkCanvas by setting the DefaultDrawingAttributes property.  You can also change the drawing attributes of strokes already present in the InkCanvas.

Existing strokes are stored in the Strokes property of the InkCanvas, which is of type StrokeCollection (in System.Windows.Ink).  This collection contains instances of Stroke objects, each of which has a DrawingAttributes property, which references an instance of the DrawingAttributes class.

In the example below, we can click on the Fatten button to thicken existing strokes.

Before clicking on Fatten:

After clicking on Fatten:

And again:

Here’s the code for the Button.Click event, which increases the Width of each Stroke already on the InkCanvas.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            foreach (Stroke s in ink.Strokes)
                s.DrawingAttributes.Width = s.DrawingAttributes.Width + 3;
        }

#487 – Specify DrawingAttributes When Drawing to an InkCanvas

You can specify a number of different drawing attributes that affect how new strokes appear when drawing on an InkCanvas control.  You set the DefaultDrawingAttributes property of the InkCanvas to an instance of the DrawingAttributes class, which contains properties that you can set to change how new strokes appear.

Properties of DrawingAttributes include:

  • Color – the color of the new stroke
  • Height – height of the brush used to draw a stroke
  • Width – width of the brush used to draw a stroke
  • FitToCurve – if true, smooths out the stroke
  • IsHighlighter – if true, stroke is somewhat translucent, simulating a highlighter
            <InkCanvas Name="ink" MinHeight="0" MinWidth="0">
                <InkCanvas.DefaultDrawingAttributes>
                    <DrawingAttributes Color="DarkGreen" Width="5" Height="20" FitToCurve="True" IsHighlighter="False" />
                </InkCanvas.DefaultDrawingAttributes>
                <Label Content="Drawing using a dark green stroke, 5x20"/>
            </InkCanvas>

Here are some examples of different values for Color, Width and Height.


Here is an example of setting the IsHighlighter property to true.

#486 – InkCanvas Supports Different Editing Modes

The InkCanvas control has an EditingMode property that allows you to change how you interact with the InkCanvas.  You can draw on it, select strokes that you’ve already drawn, or erase strokes.

EditingMode can take on one of the following values:

  • None – You can’t drawn on the InkCanvas at all
  • Ink – You can draw strokes, using a mouse or stylus

  • GestureOnly – Responds to gestures, does not allow drawing
  • InkAndGesture – Responds to gestures, or allows drawing
  • Select – You can select elements that you previously drew

  • EraseByPoint – You can use the mouse or stylus as an eraser

  • EraseByStroke – You can erase entire strokes by clicking on them

    <Window.Resources>
        <ObjectDataProvider x:Key="editingModes" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="controls:InkCanvasEditingMode"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <Border Grid.Column="0" BorderThickness="2" BorderBrush="DodgerBlue"
                Margin="5" >
            <InkCanvas MinHeight="0" MinWidth="0"
                       EditingMode="{Binding ElementName=cboEditingMode, Path=SelectedValue}"/>
        </Border>
        <ComboBox Grid.Column="1" Name="cboEditingMode" Width="100" Height="25" Margin="5"
                  ItemsSource="{Binding Source={StaticResource editingModes}}"/>
    </Grid>

#484 – InkCanvas Contains a Collection of Strokes

When you draw on an InkCanvas control, you create a series of Stroke objects.  One Stroke is created each time you hold the left mouse button down, drag the mouse to draw and then release the mouse button.  All strokes are stored in the Strokes property of the InkCanvas.

Each Stroke stores information about its drawing attributes (e.g. color, width) as well as the collection of points that make up the Stroke, stored in its StylusPoints collection.

In the example below, we use data binding to show all Strokes for an InkCanvas in an adjacent ListBox.

</pre>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="150"/>
        </Grid.ColumnDefinitions>

        <Border Grid.Row="1" BorderBrush="DodgerBlue" BorderThickness="2" Margin="5" SnapsToDevicePixels="True">
            <InkCanvas Name="ink" MinHeight="0" MinWidth="0"/>
        </Border>
        <Label Grid.Column="1" Content="Strokes:" Margin="10,5"/>
        <ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding ElementName=ink, Path=Strokes}">
             <ListBox.ItemTemplate>
                 <DataTemplate>
                     <Label Content="{Binding Path=StylusPoints, Converter={StaticResource strokeInfoConverter}}"/>
                 </DataTemplate>
             </ListBox.ItemTemplate>
        </ListBox>
    </Grid>



#483 – InkCanvas MinHeight and MinWidth

If you don’t give an InkCanvas an explicit Height or Width, but leave both to default to Auto, the InkCanvas automatically sets its MinHeight property to 250 and its MinWidth to 350.  This is done using a trigger, created in the constructor of the InkCanvas.

This can be confusing, since the same is not true for the Canvas control, whose MinHeight and MinWidth properties are initially set to 0.0.

Below, we include an InkCanvas control in a window and attach a button at each corner, so that we can better see its boundaries.  The InkCanvas sizes to fit its container (the Window), but you can see that a minimum height and width has been set.

    <InkCanvas>
        <Button Content="Bottom Left" InkCanvas.Bottom="5" InkCanvas.Left="5"/>
        <Button Content="Bottom Right" InkCanvas.Bottom="5" InkCanvas.Right="5"/>
        <Button Content="Top Right" InkCanvas.Top="5" InkCanvas.Right="5"/>
        <Button Content="Top Left" InkCanvas.Top="5" InkCanvas.Left="5"/>
    </InkCanvas>


To allow the InkCanvas to size freely, set MinHeight and MinWidth to 0.0.