방법: 사용자 지정 컨트롤에서 잉크 선택

사용자 지정 컨트롤에 IncrementalLassoHitTester를 추가하면 InkCanvas가 올가미로 잉크를 선택하는 방식과 유사하게 사용자가 올가미 도구로 잉크를 선택할 수 있도록 컨트롤을 활성화할 수 있습니다.

이 예제에서는 잉크 지원 사용자 지정 컨트롤을 만드는 데 익숙하다고 가정합니다. 잉크 입력을 허용하는 사용자 지정 컨트롤을 만들려면 잉크 입력 컨트롤 만들기를 참조하세요.

예제

사용자가 올가미를 그릴 때 IncrementalLassoHitTester는 사용자가 올가미를 완성한 후 올가미 경로의 경계 내에 어떤 스트로크가 들어갈지 예측합니다. 올가미 경로의 경계 내에 있는 것으로 확인된 스트로크는 선택된 것으로 간주할 수 있습니다. 선택된 스트로크가 선택 취소될 수도 있습니다. 예를 들어 사용자가 올가미를 그리는 동안 방향을 바꾸면 IncrementalLassoHitTester가 일부 스트로크를 선택 취소할 수 있습니다.

IncrementalLassoHitTester는 사용자가 올가미를 그리는 동안 사용자 지정 컨트롤이 응답할 수 있도록 하는 SelectionChanged 이벤트를 발생시킵니다. 예를 들어 사용자가 스트로크를 선택하고 선택 취소할 때 스트로크의 모양을 변경할 수 있습니다.

잉크 모드 관리

올가미가 컨트롤의 잉크와 다르게 나타나면 사용자에게 유용합니다. 이렇게 구현하려면 사용자가 잉크를 쓰고 있는지 또는 선택하는지를 사용자 지정 컨트롤이 추적해야 합니다. 이 작업을 수행하는 가장 쉬운 방법은 두 개의 값으로 열거형을 선언하는 것입니다. 하나는 사용자가 잉크를 쓰고 있음을 나타내는 값이고 다른 하나는 사용자가 잉크를 선택하고 있음을 나타내는 것입니다.

// Enum that keeps track of whether StrokeCollectionDemo is in ink mode
// or select mode.
public enum InkMode
{
    Ink, Select
}
' Enum that keeps track of whether StrokeCollectionDemo is in ink mode 
' or select mode.
Public Enum InkMode
    Ink
    [Select]
End Enum 'InkMode

다음으로 두 개의 DrawingAttributes를 클래스에 추가합니다. 하나는 사용자가 잉크를 쓸 때 사용하고 다른 하나는 사용자가 잉크를 선택할 때 사용합니다. 생성자에서 DrawingAttributes를 초기화하고 두 AttributeChanged 이벤트를 동일한 이벤트 처리기에 연결합니다. 그런 다음, DynamicRendererDrawingAttributes 속성을 잉크 DrawingAttributes로 설정합니다.

DrawingAttributes inkDA;
DrawingAttributes selectDA;
Private inkDA As DrawingAttributes
Private selectDA As DrawingAttributes
// In the constructor.
// Selection drawing attributes use dark gray ink.
selectDA = new DrawingAttributes();
selectDA.Color = Colors.DarkGray;

// ink drawing attributes use default attributes
inkDA = new DrawingAttributes();
inkDA.Width = 5;
inkDA.Height = 5;

inkDA.AttributeChanged += new PropertyDataChangedEventHandler(DrawingAttributesChanged);
selectDA.AttributeChanged += new PropertyDataChangedEventHandler(DrawingAttributesChanged);
' In the constructor.
' Selection drawing attributes use dark gray ink.
selectDA = New DrawingAttributes()
selectDA.Color = Colors.DarkGray

' ink drawing attributes use default attributes
inkDA = New DrawingAttributes()
inkDA.Width = 5
inkDA.Height = 5

AddHandler inkDA.AttributeChanged, _
           AddressOf DrawingAttributesChanged

AddHandler selectDA.AttributeChanged, _
           AddressOf DrawingAttributesChanged

선택 모드를 노출하는 속성을 추가합니다. 사용자가 선택 모드를 변경하면 DynamicRendererDrawingAttributes 속성을 적절한 DrawingAttributes 개체로 설정한 다음, RootVisual 속성을 InkPresenter에 다시 연결합니다.

// Property to indicate whether the user is inputting or
// selecting ink.
public InkMode Mode
{
    get
    {
        return mode;
    }

    set
    {
        mode = value;

        // Set the DrawingAttributes of the DynamicRenderer
        if (mode == InkMode.Ink)
        {
            renderer.DrawingAttributes = inkDA;
        }
        else
        {
            renderer.DrawingAttributes = selectDA;
        }

        // Reattach the visual of the DynamicRenderer to the InkPresenter.
        presenter.DetachVisuals(renderer.RootVisual);
        presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes);
    }
}
' Property to indicate whether the user is inputting or
' selecting ink.  
Public Property Mode() As InkMode
    Get
        Return Mode
    End Get

    Set(ByVal value As InkMode)
        modeState = value

        ' Set the DrawingAttributes of the DynamicRenderer
        If modeState = InkMode.Ink Then
            renderer.DrawingAttributes = inkDA
        Else
            renderer.DrawingAttributes = selectDA
        End If

        ' Reattach the visual of the DynamicRenderer to the InkPresenter.
        presenter.DetachVisuals(renderer.RootVisual)
        presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes)
    End Set
End Property

애플리케이션이 잉크 스트로크 및 선택 스트로크의 모양을 판단할 수 있도록 DrawingAttributes를 속성으로 노출합니다.

// Property to allow the user to change the pen's DrawingAttributes.
public DrawingAttributes InkDrawingAttributes
{
    get
    {
        return inkDA;
    }
}

// Property to allow the user to change the Selector'newStroke DrawingAttributes.
public DrawingAttributes SelectDrawingAttributes
{
    get
    {
        return selectDA;
    }
}
' Property to allow the user to change the pen's DrawingAttributes.
Public ReadOnly Property InkDrawingAttributes() As DrawingAttributes
    Get
        Return inkDA
    End Get
End Property

' Property to allow the user to change the Selector'newStroke DrawingAttributes.
Public ReadOnly Property SelectDrawingAttributes() As DrawingAttributes
    Get
        Return selectDA
    End Get
End Property

DrawingAttributes 개체의 속성이 변경되면 RootVisualInkPresenter에 다시 연결해야 합니다. AttributeChanged 이벤트에 대한 이벤트 처리기에서 RootVisualInkPresenter에 다시 연결합니다.

void DrawingAttributesChanged(object sender, PropertyDataChangedEventArgs e)
{
    // Reattach the visual of the DynamicRenderer to the InkPresenter
    // whenever the DrawingAttributes change.
    presenter.DetachVisuals(renderer.RootVisual);
    presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes);
}
Private Sub DrawingAttributesChanged(ByVal sender As Object, _
                             ByVal e As PropertyDataChangedEventArgs)

    ' Reattach the visual of the DynamicRenderer to the InkPresenter 
    ' whenever the DrawingAttributes change.
    presenter.DetachVisuals(renderer.RootVisual)
    presenter.AttachVisuals(renderer.RootVisual, _
                            renderer.DrawingAttributes)

End Sub

IncrementalLassoHitTester 사용

선택한 스트로크가 포함된 StrokeCollection을 만들고 초기화합니다.

// StylusPointCollection that collects the stylus points from the stylus events.
StylusPointCollection stylusPoints;
' StylusPointCollection that collects the stylus points from the stylus events.
Private stylusPoints As StylusPointCollection

사용자가 잉크 또는 올가미로 스트로크를 그리기 시작하면 선택한 스트로크를 선택 취소합니다. 그런 다음, 사용자가 올가미를 그리는 경우 GetIncrementalLassoHitTester를 호출하여 IncrementalLassoHitTester를 만들고 SelectionChanged 이벤트를 구독하고 AddPoints를 호출합니다. 이 코드는 별도의 메서드일 수 있으며 OnStylusDownOnMouseDown 메서드에서 호출됩니다.

private void InitializeHitTester(StylusPointCollection collectedPoints)
{
    // Deselect any selected strokes.
    foreach (Stroke selectedStroke in selectedStrokes)
    {
        selectedStroke.DrawingAttributes.Color = inkDA.Color;
    }
    selectedStrokes.Clear();

    if (mode == InkMode.Select)
    {
        // Remove the previously drawn lasso, if it exists.
        if (lassoPath != null)
        {
            presenter.Strokes.Remove(lassoPath);
            lassoPath = null;
        }

        selectionTester =
            presenter.Strokes.GetIncrementalLassoHitTester(80);
        selectionTester.SelectionChanged +=
            new LassoSelectionChangedEventHandler(selectionTester_SelectionChanged);
        selectionTester.AddPoints(collectedPoints);
    }
}
Private Sub InitializeHitTester(ByVal collectedPoints As StylusPointCollection)

    ' Deselect any selected strokes.
    Dim selectedStroke As Stroke
    For Each selectedStroke In selectedStrokes
        selectedStroke.DrawingAttributes.Color = inkDA.Color
    Next selectedStroke
    selectedStrokes.Clear()

    If modeState = InkMode.Select Then
        ' Remove the previously drawn lasso, if it exists.
        If Not (lassoPath Is Nothing) Then
            presenter.Strokes.Remove(lassoPath)
            lassoPath = Nothing
        End If

        selectionTester = presenter.Strokes.GetIncrementalLassoHitTester(80)
        AddHandler selectionTester.SelectionChanged, AddressOf selectionTester_SelectionChanged
        selectionTester.AddPoints(collectedPoints)
    End If

End Sub

사용자가 올가미를 그리는 동안 스타일러스 포인트를 IncrementalLassoHitTester에 추가합니다. OnStylusMove, OnStylusUp, OnMouseMoveOnMouseLeftButtonUp 메서드에서 다음 메서드를 호출합니다.

private void AddPointsToHitTester(StylusPointCollection collectedPoints)
{

    if (mode == InkMode.Select &&
        selectionTester != null &&
        selectionTester.IsValid)
    {
        // When the control is selecting strokes, add the
        // stylus packetList to selectionTester.
        selectionTester.AddPoints(collectedPoints);
    }
}
Private Sub AddPointsToHitTester(ByVal collectedPoints As StylusPointCollection)

    If modeState = InkMode.Select AndAlso _
       Not selectionTester Is Nothing AndAlso _
       selectionTester.IsValid Then

        ' When the control is selecting strokes, add the
        ' stylus packetList to selectionTester.
        selectionTester.AddPoints(collectedPoints)
    End If

End Sub

사용자가 스트로크를 선택하거나 선택 취소할 때 응답하도록 IncrementalLassoHitTester.SelectionChanged 이벤트를 처리합니다. LassoSelectionChangedEventArgs 클래스에는 각각 선택되고 선택되지 않은 스트로크를 가져오는 SelectedStrokesDeselectedStrokes 속성이 있습니다.

void selectionTester_SelectionChanged(object sender,
    LassoSelectionChangedEventArgs args)
{
    // Change the color of all selected strokes to red.
    foreach (Stroke selectedStroke in args.SelectedStrokes)
    {
        selectedStroke.DrawingAttributes.Color = Colors.Red;
        selectedStrokes.Add(selectedStroke);
    }

    // Change the color of all unselected strokes to
    // their original color.
    foreach (Stroke unselectedStroke in args.DeselectedStrokes)
    {
        unselectedStroke.DrawingAttributes.Color = inkDA.Color;
        selectedStrokes.Remove(unselectedStroke);
    }
}
Private Sub selectionTester_SelectionChanged(ByVal sender As Object, _
                                     ByVal args As LassoSelectionChangedEventArgs)

    ' Change the color of all selected strokes to red.
    Dim selectedStroke As Stroke
    For Each selectedStroke In args.SelectedStrokes
        selectedStroke.DrawingAttributes.Color = Colors.Red
        selectedStrokes.Add(selectedStroke)
    Next selectedStroke

    ' Change the color of all unselected strokes to 
    ' their original color.
    Dim unselectedStroke As Stroke
    For Each unselectedStroke In args.DeselectedStrokes
        unselectedStroke.DrawingAttributes.Color = inkDA.Color
        selectedStrokes.Remove(unselectedStroke)
    Next unselectedStroke

End Sub

사용자가 올가미 그리기를 마치면 SelectionChanged 이벤트 구독을 취소하고 EndHitTesting을 호출합니다.

if (mode == InkMode.Select && lassoPath == null)
{
    // Add the lasso to the InkPresenter and add the packetList
    // to selectionTester.
    lassoPath = newStroke;
    lassoPath.DrawingAttributes = selectDA.Clone();
    presenter.Strokes.Add(lassoPath);
    selectionTester.SelectionChanged -= new LassoSelectionChangedEventHandler
                    (selectionTester_SelectionChanged);
    selectionTester.EndHitTesting();
}
If modeState = InkMode.Select AndAlso lassoPath Is Nothing Then
    ' Add the lasso to the InkPresenter and add the packetList
    ' to selectionTester.
    lassoPath = newStroke
    lassoPath.DrawingAttributes = selectDA.Clone()
    presenter.Strokes.Add(lassoPath)
    RemoveHandler selectionTester.SelectionChanged, _
                  AddressOf selectionTester_SelectionChanged
    selectionTester.EndHitTesting()
End If

총정리

다음 예제는 사용자가 올가미가 있는 잉크를 선택할 수 있도록 하는 사용자 지정 컨트롤입니다.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Ink;

// Enum that keeps track of whether StrokeCollectionDemo is in ink mode
// or select mode.
public enum InkMode
{
    Ink, Select
}

// This control allows the user to input and select ink.  When the
// user selects ink, the lasso remains visible until they erase, or clip
// the selected strokes, or clear the selection.  When the control is
// in selection mode, strokes that are selected turn red.
public class InkSelector : Label
{
    InkMode mode;

    DrawingAttributes inkDA;
    DrawingAttributes selectDA;

    InkPresenter presenter;
    IncrementalLassoHitTester selectionTester;
    StrokeCollection selectedStrokes = new StrokeCollection();

    // StylusPointCollection that collects the stylus points from the stylus events.
    StylusPointCollection stylusPoints;
    // Stroke that represents the lasso.
    Stroke lassoPath;

    DynamicRenderer renderer;

    public InkSelector()
    {
        mode = InkMode.Ink;

        // Use an InkPresenter to display the strokes on the custom control.
        presenter = new InkPresenter();
        this.Content = presenter;

        // In the constructor.
        // Selection drawing attributes use dark gray ink.
        selectDA = new DrawingAttributes();
        selectDA.Color = Colors.DarkGray;

        // ink drawing attributes use default attributes
        inkDA = new DrawingAttributes();
        inkDA.Width = 5;
        inkDA.Height = 5;

        inkDA.AttributeChanged += new PropertyDataChangedEventHandler(DrawingAttributesChanged);
        selectDA.AttributeChanged += new PropertyDataChangedEventHandler(DrawingAttributesChanged);

        // Add a DynmaicRenderer to the control so ink appears
        // to "flow" from the tablet pen.
        renderer = new DynamicRenderer();
        renderer.DrawingAttributes = inkDA;
        this.StylusPlugIns.Add(renderer);
        presenter.AttachVisuals(renderer.RootVisual,
            renderer.DrawingAttributes);
    }

    static InkSelector()
    {
        // Allow ink to be drawn only within the bounds of the control.
        Type owner = typeof(InkSelector);
        ClipToBoundsProperty.OverrideMetadata(owner,
            new FrameworkPropertyMetadata(true));
    }

    // Prepare to collect stylus packets. If Mode is set to Select,
    // get the IncrementalHitTester from the InkPresenter'newStroke
    // StrokeCollection and subscribe to its StrokeHitChanged event.
    protected override void OnStylusDown(StylusDownEventArgs e)
    {
        base.OnStylusDown(e);

        Stylus.Capture(this);

        // Create a new StylusPointCollection using the StylusPointDescription
        // from the stylus points in the StylusDownEventArgs.
        stylusPoints = new StylusPointCollection();
        StylusPointCollection eventPoints = e.GetStylusPoints(this, stylusPoints.Description);

        stylusPoints.Add(eventPoints);

        InitializeHitTester(eventPoints);
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);

        Mouse.Capture(this);

        if (e.StylusDevice != null)
        {
            return;
        }

        Point pt = e.GetPosition(this);

        StylusPointCollection collectedPoints = new StylusPointCollection(new Point[] { pt });

        stylusPoints = new StylusPointCollection();

        stylusPoints.Add(collectedPoints);

        InitializeHitTester(collectedPoints);
    }
    private void InitializeHitTester(StylusPointCollection collectedPoints)
    {
        // Deselect any selected strokes.
        foreach (Stroke selectedStroke in selectedStrokes)
        {
            selectedStroke.DrawingAttributes.Color = inkDA.Color;
        }
        selectedStrokes.Clear();

        if (mode == InkMode.Select)
        {
            // Remove the previously drawn lasso, if it exists.
            if (lassoPath != null)
            {
                presenter.Strokes.Remove(lassoPath);
                lassoPath = null;
            }

            selectionTester =
                presenter.Strokes.GetIncrementalLassoHitTester(80);
            selectionTester.SelectionChanged +=
                new LassoSelectionChangedEventHandler(selectionTester_SelectionChanged);
            selectionTester.AddPoints(collectedPoints);
        }
    }

    // Collect the stylus packets as the stylus moves.
    protected override void OnStylusMove(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }

        StylusPointCollection collectedPoints = e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(collectedPoints);
        AddPointsToHitTester(collectedPoints);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {

        base.OnMouseMove(e);

        if (e.StylusDevice != null)
        {
            return;
        }

        if (e.LeftButton == MouseButtonState.Released)
        {
            return;
        }

        stylusPoints ??= new StylusPointCollection();

        Point pt = e.GetPosition(this);

        StylusPointCollection collectedPoints = new StylusPointCollection(new Point[] { pt });

        stylusPoints.Add(collectedPoints);

        AddPointsToHitTester(collectedPoints);
    }

    private void AddPointsToHitTester(StylusPointCollection collectedPoints)
    {

        if (mode == InkMode.Select &&
            selectionTester != null &&
            selectionTester.IsValid)
        {
            // When the control is selecting strokes, add the
            // stylus packetList to selectionTester.
            selectionTester.AddPoints(collectedPoints);
        }
    }

    // When the user lifts the stylus, create a Stroke from the
    // collected stylus points and add it to the InkPresenter.
    // When the control is selecting strokes, add the
    // point data to the IncrementalHitTester.
    protected override void OnStylusUp(StylusEventArgs e)
    {
        stylusPoints ??= new StylusPointCollection();
        StylusPointCollection collectedPoints =
            e.GetStylusPoints(this, stylusPoints.Description);

        stylusPoints.Add(collectedPoints);
        AddPointsToHitTester(collectedPoints);
        AddStrokeToPresenter();
        stylusPoints = null;

        Stylus.Capture(null);
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {

        base.OnMouseLeftButtonUp(e);

        if (e.StylusDevice != null) return;

        if (stylusPoints == null) stylusPoints = new StylusPointCollection();

        Point pt = e.GetPosition(this);

        StylusPointCollection collectedPoints = new StylusPointCollection(new Point[] { pt });

        stylusPoints.Add(collectedPoints);
        AddPointsToHitTester(collectedPoints);
        AddStrokeToPresenter();

        stylusPoints = null;

        Mouse.Capture(null);
    }

    private void AddStrokeToPresenter()
    {
        Stroke newStroke = new Stroke(stylusPoints);

        if (mode == InkMode.Ink)
        {
            // Add the stroke to the InkPresenter.
            newStroke.DrawingAttributes = inkDA.Clone();
            presenter.Strokes.Add(newStroke);
        }

        if (mode == InkMode.Select && lassoPath == null)
        {
            // Add the lasso to the InkPresenter and add the packetList
            // to selectionTester.
            lassoPath = newStroke;
            lassoPath.DrawingAttributes = selectDA.Clone();
            presenter.Strokes.Add(lassoPath);
            selectionTester.SelectionChanged -= new LassoSelectionChangedEventHandler
                            (selectionTester_SelectionChanged);
            selectionTester.EndHitTesting();
        }
    }

    void selectionTester_SelectionChanged(object sender,
        LassoSelectionChangedEventArgs args)
    {
        // Change the color of all selected strokes to red.
        foreach (Stroke selectedStroke in args.SelectedStrokes)
        {
            selectedStroke.DrawingAttributes.Color = Colors.Red;
            selectedStrokes.Add(selectedStroke);
        }

        // Change the color of all unselected strokes to
        // their original color.
        foreach (Stroke unselectedStroke in args.DeselectedStrokes)
        {
            unselectedStroke.DrawingAttributes.Color = inkDA.Color;
            selectedStrokes.Remove(unselectedStroke);
        }
    }

    // Property to indicate whether the user is inputting or
    // selecting ink.
    public InkMode Mode
    {
        get
        {
            return mode;
        }

        set
        {
            mode = value;

            // Set the DrawingAttributes of the DynamicRenderer
            if (mode == InkMode.Ink)
            {
                renderer.DrawingAttributes = inkDA;
            }
            else
            {
                renderer.DrawingAttributes = selectDA;
            }

            // Reattach the visual of the DynamicRenderer to the InkPresenter.
            presenter.DetachVisuals(renderer.RootVisual);
            presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes);
        }
    }
    void DrawingAttributesChanged(object sender, PropertyDataChangedEventArgs e)
    {
        // Reattach the visual of the DynamicRenderer to the InkPresenter
        // whenever the DrawingAttributes change.
        presenter.DetachVisuals(renderer.RootVisual);
        presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes);
    }

    // Property to allow the user to change the pen's DrawingAttributes.
    public DrawingAttributes InkDrawingAttributes
    {
        get
        {
            return inkDA;
        }
    }

    // Property to allow the user to change the Selector'newStroke DrawingAttributes.
    public DrawingAttributes SelectDrawingAttributes
    {
        get
        {
            return selectDA;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Input
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Ink


' Enum that keeps track of whether StrokeCollectionDemo is in ink mode 
' or select mode.
Public Enum InkMode
    Ink
    [Select]
End Enum 'InkMode

' This control allows the user to input and select ink.  When the
' user selects ink, the lasso remains visible until they erase, or clip
' the selected strokes, or clear the selection.  When the control is
' in selection mode, strokes that are selected turn red.
Public Class InkSelector
    Inherits Label

    Private modeState As InkMode

    Private inkDA As DrawingAttributes
    Private selectDA As DrawingAttributes

    Private presenter As InkPresenter
    Private selectionTester As IncrementalLassoHitTester
    Private selectedStrokes As New StrokeCollection()

    ' StylusPointCollection that collects the stylus points from the stylus events.
    Private stylusPoints As StylusPointCollection

    ' Stroke that represents the lasso.
    Private lassoPath As Stroke

    Private renderer As DynamicRenderer


    Public Sub New()
        modeState = InkMode.Ink

        ' Use an InkPresenter to display the strokes on the custom control.
        presenter = New InkPresenter()
        Me.Content = presenter

        ' In the constructor.
        ' Selection drawing attributes use dark gray ink.
        selectDA = New DrawingAttributes()
        selectDA.Color = Colors.DarkGray

        ' ink drawing attributes use default attributes
        inkDA = New DrawingAttributes()
        inkDA.Width = 5
        inkDA.Height = 5

        AddHandler inkDA.AttributeChanged, _
                   AddressOf DrawingAttributesChanged

        AddHandler selectDA.AttributeChanged, _
                   AddressOf DrawingAttributesChanged

        ' Add a DynmaicRenderer to the control so ink appears
        ' to "flow" from the tablet pen.
        renderer = New DynamicRenderer()
        renderer.DrawingAttributes = inkDA
        Me.StylusPlugIns.Add(renderer)
        presenter.AttachVisuals(renderer.RootVisual, _
            renderer.DrawingAttributes)

    End Sub


    Shared Sub New()
        ' Allow ink to be drawn only within the bounds of the control.
        Dim owner As Type = GetType(InkSelector)
        ClipToBoundsProperty.OverrideMetadata(owner, _
            New FrameworkPropertyMetadata(True))

    End Sub

    ' Prepare to collect stylus packets. If Mode is set to Select,  
    ' get the IncrementalHitTester from the InkPresenter'newStroke 
    ' StrokeCollection and subscribe to its StrokeHitChanged event.
    Protected Overrides Sub OnStylusDown(ByVal e As StylusDownEventArgs)
        MyBase.OnStylusDown(e)

        Stylus.Capture(Me)

        ' Create a new StylusPointCollection using the StylusPointDescription
        ' from the stylus points in the StylusDownEventArgs.
        stylusPoints = New StylusPointCollection()
        Dim eventPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)

        stylusPoints.Add(eventPoints)

        InitializeHitTester(eventPoints)

    End Sub


    Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
        MyBase.OnMouseLeftButtonDown(e)

        Mouse.Capture(Me)

        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        Dim pt As Point = e.GetPosition(Me)

        Dim collectedPoints As New StylusPointCollection(New Point() {pt})

        stylusPoints = New StylusPointCollection()

        stylusPoints.Add(collectedPoints)

        InitializeHitTester(collectedPoints)

    End Sub


    Private Sub InitializeHitTester(ByVal collectedPoints As StylusPointCollection)

        ' Deselect any selected strokes.
        Dim selectedStroke As Stroke
        For Each selectedStroke In selectedStrokes
            selectedStroke.DrawingAttributes.Color = inkDA.Color
        Next selectedStroke
        selectedStrokes.Clear()

        If modeState = InkMode.Select Then
            ' Remove the previously drawn lasso, if it exists.
            If Not (lassoPath Is Nothing) Then
                presenter.Strokes.Remove(lassoPath)
                lassoPath = Nothing
            End If

            selectionTester = presenter.Strokes.GetIncrementalLassoHitTester(80)
            AddHandler selectionTester.SelectionChanged, AddressOf selectionTester_SelectionChanged
            selectionTester.AddPoints(collectedPoints)
        End If

    End Sub

    ' Collect the stylus packets as the stylus moves.
    Protected Overrides Sub OnStylusMove(ByVal e As StylusEventArgs)

        If stylusPoints Is Nothing Then
            Return
        End If

        Dim collectedPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(collectedPoints)
        AddPointsToHitTester(collectedPoints)

    End Sub


    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)

        MyBase.OnMouseMove(e)

        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        If e.LeftButton = MouseButtonState.Released Then
            Return
        End If

        If stylusPoints Is Nothing Then
            stylusPoints = New StylusPointCollection()
        End If

        Dim pt As Point = e.GetPosition(Me)

        Dim collectedPoints As New StylusPointCollection(New Point() {pt})

        stylusPoints.Add(collectedPoints)

        AddPointsToHitTester(collectedPoints)

    End Sub


    Private Sub AddPointsToHitTester(ByVal collectedPoints As StylusPointCollection)

        If modeState = InkMode.Select AndAlso _
           Not selectionTester Is Nothing AndAlso _
           selectionTester.IsValid Then

            ' When the control is selecting strokes, add the
            ' stylus packetList to selectionTester.
            selectionTester.AddPoints(collectedPoints)
        End If

    End Sub

    ' When the user lifts the stylus, create a Stroke from the
    ' collected stylus points and add it to the InkPresenter.
    ' When the control is selecting strokes, add the
    ' point data to the IncrementalHitTester.
    Protected Overrides Sub OnStylusUp(ByVal e As StylusEventArgs)

        If stylusPoints Is Nothing Then
            stylusPoints = New StylusPointCollection()
        End If

        Dim collectedPoints As StylusPointCollection = _
            e.GetStylusPoints(Me, stylusPoints.Description)

        stylusPoints.Add(collectedPoints)
        AddPointsToHitTester(collectedPoints)
        AddStrokeToPresenter()

        stylusPoints = Nothing

        Stylus.Capture(Nothing)

    End Sub


    Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As MouseButtonEventArgs)

        MyBase.OnMouseLeftButtonUp(e)

        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
        If stylusPoints Is Nothing Then
            stylusPoints = New StylusPointCollection()
        End If
        Dim pt As Point = e.GetPosition(Me)

        Dim collectedPoints As New StylusPointCollection(New Point() {pt})

        stylusPoints.Add(collectedPoints)
        AddPointsToHitTester(collectedPoints)
        AddStrokeToPresenter()

        stylusPoints = Nothing

        Mouse.Capture(Nothing)

    End Sub


    Private Sub AddStrokeToPresenter()
        Dim newStroke As New Stroke(stylusPoints)

        If modeState = InkMode.Ink Then
            ' Add the stroke to the InkPresenter.
            newStroke.DrawingAttributes = inkDA.Clone()
            presenter.Strokes.Add(newStroke)
        End If

        If modeState = InkMode.Select AndAlso lassoPath Is Nothing Then
            ' Add the lasso to the InkPresenter and add the packetList
            ' to selectionTester.
            lassoPath = newStroke
            lassoPath.DrawingAttributes = selectDA.Clone()
            presenter.Strokes.Add(lassoPath)
            RemoveHandler selectionTester.SelectionChanged, _
                          AddressOf selectionTester_SelectionChanged
            selectionTester.EndHitTesting()
        End If

    End Sub

    Private Sub selectionTester_SelectionChanged(ByVal sender As Object, _
                                         ByVal args As LassoSelectionChangedEventArgs)

        ' Change the color of all selected strokes to red.
        Dim selectedStroke As Stroke
        For Each selectedStroke In args.SelectedStrokes
            selectedStroke.DrawingAttributes.Color = Colors.Red
            selectedStrokes.Add(selectedStroke)
        Next selectedStroke

        ' Change the color of all unselected strokes to 
        ' their original color.
        Dim unselectedStroke As Stroke
        For Each unselectedStroke In args.DeselectedStrokes
            unselectedStroke.DrawingAttributes.Color = inkDA.Color
            selectedStrokes.Remove(unselectedStroke)
        Next unselectedStroke

    End Sub

    ' Property to indicate whether the user is inputting or
    ' selecting ink.  
    Public Property Mode() As InkMode
        Get
            Return Mode
        End Get

        Set(ByVal value As InkMode)
            modeState = value

            ' Set the DrawingAttributes of the DynamicRenderer
            If modeState = InkMode.Ink Then
                renderer.DrawingAttributes = inkDA
            Else
                renderer.DrawingAttributes = selectDA
            End If

            ' Reattach the visual of the DynamicRenderer to the InkPresenter.
            presenter.DetachVisuals(renderer.RootVisual)
            presenter.AttachVisuals(renderer.RootVisual, renderer.DrawingAttributes)
        End Set
    End Property
    Private Sub DrawingAttributesChanged(ByVal sender As Object, _
                                 ByVal e As PropertyDataChangedEventArgs)

        ' Reattach the visual of the DynamicRenderer to the InkPresenter 
        ' whenever the DrawingAttributes change.
        presenter.DetachVisuals(renderer.RootVisual)
        presenter.AttachVisuals(renderer.RootVisual, _
                                renderer.DrawingAttributes)

    End Sub

    ' Property to allow the user to change the pen's DrawingAttributes.
    Public ReadOnly Property InkDrawingAttributes() As DrawingAttributes
        Get
            Return inkDA
        End Get
    End Property

    ' Property to allow the user to change the Selector'newStroke DrawingAttributes.
    Public ReadOnly Property SelectDrawingAttributes() As DrawingAttributes
        Get
            Return selectDA
        End Get
    End Property

End Class

참고 항목