次の方法で共有


インク入力コントロールの作成

更新 : 2007 年 11 月

インクのレンダリングを動的にも静的にも行うカスタム コントロールを作成できます。つまり、ユーザーがストロークを描画したときに、タブレット ペンから "流れる" ようにインクが表示されるようにインクをレンダリングしたり、タブレット ペンからの入力、クリップボードからの貼り付け、ファイルからの読み込みのいずれかによってインクをコントロールに追加した後にそのインクを表示したりします。インクを動的にレンダリングするには、コントロールが DynamicRenderer を使用する必要があります。インクを静的にレンダリングするには、スタイラス イベント メソッド (OnStylusDownOnStylusMove、および OnStylusUp) をオーバーライドして、StylusPoint データの収集、ストロークの作成、これらのメソッドの (コントロール上でインクをレンダリングする) InkPresenter への追加を行う必要があります。

このトピックは、次の内容で構成されています。

  • 方法 : スタイラス ポイント データを収集してインク ストロークを作成する

  • 方法 : コントロールでマウスからの入力を受け付けられるようにする

  • スタイラスおよびマウス双方からの入力

  • 追加のプラグインと DynamicRenderer の使用

  • まとめ

方法 : スタイラス ポイント データを収集してインク ストロークを作成する

インク ストロークを収集して管理するコントロールを作成するには、次の手順を実行します。

  1. Control のクラス、または Control の派生クラスのいずれか (Label など) を派生します。

    Imports System
    Imports System.Collections.Generic
    Imports System.Text
    Imports System.Windows.Ink
    Imports System.Windows.Input
    Imports System.Windows.Input.StylusPlugIns
    Imports System.Windows.Controls
    Imports System.Windows
    
    
    ...
    
    
    Class InkControl
        Inherits Label
    
    
    ...
    
    
    End Class 'StylusControl
    
    using System;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Input.StylusPlugIns;
    using System.Windows.Controls;
    using System.Windows;
    
    
    ...
    
    
    class InkControl : Label
    {
    
    
    ...
    
    
    }
    
  2. InkPresenter をそのクラスに追加し、Content プロパティを新しい InkPresenter に設定します。

    Private ip As InkPresenter
    
    Public Sub New()
        ' Add an InkPresenter for drawing.
        ip = New InkPresenter()
        Me.Content = ip
    
    End Sub
    
    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. AttachVisuals メソッドを呼び出して DynamicRendererRootVisualInkPresenter に割り当て、DynamicRendererStylusPlugIns コレクションに追加します。これにより、コントロールによってスタイラス ポイント データが収集されたとおりに InkPresenter がインクを表示できるようになります。

    Public Sub New()
    
    
    ...
    
    
        ' Add a dynamic renderer that 
        ' draws ink as it "flows" from the stylus.
        dr = New DynamicRenderer()
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes)
        Me.StylusPlugIns.Add(dr)
    
    End Sub
    
    public InkControl()
    {
    
    
    ...
    
    
        // Add a dynamic renderer that 
        // draws ink as it "flows" from the stylus.
        dr = new DynamicRenderer();
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
        this.StylusPlugIns.Add(dr);
    
    }
    
  4. OnStylusDown メソッドをオーバーライドします。このメソッドでは、Capture を呼び出してスタイラスをキャプチャします。スタイラスをキャプチャすることにより、コントロールは、スタイラスがコントロールの境界を離れても StylusMove イベントおよび StylusUp イベントを継続して受け取ります。これは、厳密には必須ではありませんが、快適なユーザー エクスペリエンスのためには、たいてい必要です。新しい StylusPointCollection を作成し、StylusPoint データを収集します。最後に、StylusPoint データの最初のセットを StylusPointCollection に追加します。

    Protected Overrides Sub OnStylusDown(ByVal e As StylusDownEventArgs)
        ' Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(Me)
    
        ' Allocate memory for the StylusPointsCollection and
        ' add the StylusPoints that have come in so far.
        stylusPoints = New StylusPointCollection()
        Dim eventPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
    
        stylusPoints.Add(eventPoints)
    
    End Sub 'OnStylusDown
    
    protected override void OnStylusDown(StylusDownEventArgs e)
    {
        // Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(this);
    
        // Allocate memory for the StylusPointsCollection and
        // add the StylusPoints that have come in so far.
        stylusPoints = new StylusPointCollection();
        StylusPointCollection eventPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
    
        stylusPoints.Add(eventPoints);
    
    }
    
  5. OnStylusMove メソッドをオーバーライドし、StylusPoint データを、作成しておいた StylusPointCollection オブジェクトに追加します。

    Protected Overrides Sub OnStylusMove(ByVal e As StylusEventArgs)
    
        If stylusPoints Is Nothing Then
            Return
        End If
    
        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)
    
    End Sub 'OnStylusMove
    
    protected override void OnStylusMove(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }
    
        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    }
    
  6. OnStylusUp メソッドをオーバーライドし、StylusPointCollection データを持つ新しい Stroke を作成します。作成した新しい StrokeInkPresenterStrokes コレクションに追加し、スタイラス キャプチャを解放します。

    Protected Overrides Sub OnStylusUp(ByVal e As StylusEventArgs)
        ' Allocate memory for the StylusPointsCollection, if necessary.
        If stylusPoints Is Nothing Then
            Return
        End If
    
        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)
    
        ' Create a new stroke from all the StylusPoints since OnStylusDown.
        Dim stroke As New Stroke(stylusPoints)
    
        ' Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke)
    
        ' Clear the StylusPointsCollection.
        stylusPoints = Nothing
    
        ' Release stylus capture.
        Stylus.Capture(Nothing)
    
    End Sub 'OnStylusUp
    
    protected override void OnStylusUp(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }
    
        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    
        // Create a new stroke from all the StylusPoints since OnStylusDown.
        Stroke stroke = new Stroke(stylusPoints);
    
        // Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke);
    
        // Clear the StylusPointsCollection.
        stylusPoints = null;
    
        // Release stylus capture.
        Stylus.Capture(null);
    }
    

方法 : コントロールでマウスからの入力を受け付けられるようにする

前の例で作成したコントロールをアプリケーションに追加して実行した場合に、マウスを入力デバイスとして使用すると、ストロークが永続化されないことがわかります。マウスを入力デバイスとして使用する場合にもストロークを永続化するには、次の手順を実行します。

  1. OnMouseLeftButtonDown をオーバーライドし、新しい StylusPointCollection を作成します。イベント発生時のマウスの位置を取得し、そのポイント データを使用して StylusPoint を作成して、その StylusPointStylusPointCollection に追加します。

    Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
    
        MyBase.OnMouseLeftButtonDown(e)
    
        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
    
        ' Start collecting the points.
        stylusPoints = New StylusPointCollection()
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
    End Sub 'OnMouseLeftButtonDown
    
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    
        base.OnMouseLeftButtonDown(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        // Start collecting the points.
        stylusPoints = new StylusPointCollection();
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    
    }
    
  2. OnMouseMove メソッドをオーバーライドします。イベント発生時のマウスの位置を取得し、そのポイント データを使用して StylusPoint を作成します。StylusPoint を作成しておいた StylusPointCollection オブジェクトに追加します。

    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
    
        MyBase.OnMouseMove(e)
    
        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If
    
        ' Don't collect points unless the left mouse button
        ' is down.
        If e.LeftButton = MouseButtonState.Released Then
            Return
        End If
    
        If stylusPoints Is Nothing Then
            Return
        End If
    
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
    End Sub 'OnMouseMove
    
    protected override void OnMouseMove(MouseEventArgs e)
    {
    
        base.OnMouseMove(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        // Don't collect points unless the left mouse button
        // is down.
        if (e.LeftButton == MouseButtonState.Released || 
            stylusPoints == null)
        {
            return;
        }
    
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    }
    
  3. OnMouseLeftButtonUp メソッドをオーバーライドします。StylusPointCollection データを持つ新しい Stroke を作成し、作成したその新しい StrokeInkPresenterStrokes コレクションに追加します。

    Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As MouseButtonEventArgs)
    
        MyBase.OnMouseLeftButtonUp(e)
    
        ' If a stylus generated this event, return.
        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)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))
    
        ' Create a stroke and add it to the InkPresenter.
        Dim stroke As New Stroke(stylusPoints)
        stroke.DrawingAttributes = dr.DrawingAttributes
        ip.Strokes.Add(stroke)
    
        stylusPoints = Nothing
    
    End Sub 'OnMouseLeftButtonUp 
    
    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
    
        base.OnMouseLeftButtonUp(e);
    
        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }
    
        if (stylusPoints == null)
        {
            return;
        }
    
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    
        // Create a stroke and add it to the InkPresenter.
        Stroke stroke = new Stroke(stylusPoints);
        stroke.DrawingAttributes = dr.DrawingAttributes;
        ip.Strokes.Add(stroke);
    
        stylusPoints = null;
    
    }
    

スタイラスおよびマウス双方からの入力

ユーザーがマウスまたはペンのいずれかを使用した場合にインクを収集するカスタム コントロールの例を次に示します。

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Ink
Imports System.Windows.Input
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Controls
Imports System.Windows


...


' A control for managing ink input
Class InkControl
    Inherits Label
    Private ip As InkPresenter
    Private dr As DynamicRenderer

    ' The StylusPointsCollection that gathers points 
    ' before Stroke from is created.
    Private stylusPoints As StylusPointCollection = Nothing


    Public Sub New()
        ' Add an InkPresenter for drawing.
        ip = New InkPresenter()
        Me.Content = ip

        ' Add a dynamic renderer that 
        ' draws ink as it "flows" from the stylus.
        dr = New DynamicRenderer()
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes)
        Me.StylusPlugIns.Add(dr)

        Dim cdr As New CustomDynamicRenderer()
        ip.AttachVisuals(cdr.RootVisual, cdr.DrawingAttributes)
        Me.StylusPlugIns.Add(cdr)

    End Sub 'New

    Shared Sub New()

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

    End Sub 'New

    Protected Overrides Sub OnStylusDown(ByVal e As StylusDownEventArgs)
        ' Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(Me)

        ' Allocate memory for the StylusPointsCollection and
        ' add the StylusPoints that have come in so far.
        stylusPoints = New StylusPointCollection()
        Dim eventPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)

        stylusPoints.Add(eventPoints)

    End Sub 'OnStylusDown

    Protected Overrides Sub OnStylusMove(ByVal e As StylusEventArgs)

        If stylusPoints Is Nothing Then
            Return
        End If

        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)

    End Sub 'OnStylusMove

    Protected Overrides Sub OnStylusUp(ByVal e As StylusEventArgs)
        ' Allocate memory for the StylusPointsCollection, if necessary.
        If stylusPoints Is Nothing Then
            Return
        End If

        ' Add the StylusPoints that have come in since the 
        ' last call to OnStylusMove.
        Dim newStylusPoints As StylusPointCollection = e.GetStylusPoints(Me, stylusPoints.Description)
        stylusPoints.Add(newStylusPoints)

        ' Create a new stroke from all the StylusPoints since OnStylusDown.
        Dim stroke As New Stroke(stylusPoints)

        ' Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke)

        ' Clear the StylusPointsCollection.
        stylusPoints = Nothing

        ' Release stylus capture.
        Stylus.Capture(Nothing)

    End Sub 'OnStylusUp

    Protected Overrides Sub OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)

        MyBase.OnMouseLeftButtonDown(e)

        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        ' Start collecting the points.
        stylusPoints = New StylusPointCollection()
        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

    End Sub 'OnMouseLeftButtonDown

    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)

        MyBase.OnMouseMove(e)

        ' If a stylus generated this event, return.
        If Not (e.StylusDevice Is Nothing) Then
            Return
        End If

        ' Don't collect points unless the left mouse button
        ' is down.
        If e.LeftButton = MouseButtonState.Released Then
            Return
        End If

        If stylusPoints Is Nothing Then
            Return
        End If

        Dim pt As Point = e.GetPosition(Me)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

    End Sub 'OnMouseMove

    Protected Overrides Sub OnMouseLeftButtonUp(ByVal e As MouseButtonEventArgs)

        MyBase.OnMouseLeftButtonUp(e)

        ' If a stylus generated this event, return.
        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)
        stylusPoints.Add(New StylusPoint(pt.X, pt.Y))

        ' Create a stroke and add it to the InkPresenter.
        Dim stroke As New Stroke(stylusPoints)
        stroke.DrawingAttributes = dr.DrawingAttributes
        ip.Strokes.Add(stroke)

        stylusPoints = Nothing

    End Sub 'OnMouseLeftButtonUp 
End Class 'StylusControl
using System;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Controls;
using System.Windows;


...


// A control for managing ink input
class InkControl : Label
{
    InkPresenter ip;
    DynamicRenderer dr;

    // The StylusPointsCollection that gathers points 
    // before Stroke from is created.
    StylusPointCollection stylusPoints = null;

    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;

        // Add a dynamic renderer that 
        // draws ink as it "flows" from the stylus.
        dr = new DynamicRenderer();
        ip.AttachVisuals(dr.RootVisual, dr.DrawingAttributes);
        this.StylusPlugIns.Add(dr);

    }

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

    protected override void OnStylusDown(StylusDownEventArgs e)
    {
        // Capture the stylus so all stylus input is routed to this control.
        Stylus.Capture(this);

        // Allocate memory for the StylusPointsCollection and
        // add the StylusPoints that have come in so far.
        stylusPoints = new StylusPointCollection();
        StylusPointCollection eventPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);

        stylusPoints.Add(eventPoints);

    }

    protected override void OnStylusMove(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }

        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);
    }

    protected override void OnStylusUp(StylusEventArgs e)
    {
        if (stylusPoints == null)
        {
            return;
        }

        // Add the StylusPoints that have come in since the 
        // last call to OnStylusMove.
        StylusPointCollection newStylusPoints = 
            e.GetStylusPoints(this, stylusPoints.Description);
        stylusPoints.Add(newStylusPoints);

        // Create a new stroke from all the StylusPoints since OnStylusDown.
        Stroke stroke = new Stroke(stylusPoints);

        // Add the new stroke to the Strokes collection of the InkPresenter.
        ip.Strokes.Add(stroke);

        // Clear the StylusPointsCollection.
        stylusPoints = null;

        // Release stylus capture.
        Stylus.Capture(null);
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {

        base.OnMouseLeftButtonDown(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        // Start collecting the points.
        stylusPoints = new StylusPointCollection();
        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

    }

    protected override void OnMouseMove(MouseEventArgs e)
    {

        base.OnMouseMove(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        // Don't collect points unless the left mouse button
        // is down.
        if (e.LeftButton == MouseButtonState.Released || 
            stylusPoints == null)
        {
            return;
        }

        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {

        base.OnMouseLeftButtonUp(e);

        // If a stylus generated this event, return.
        if (e.StylusDevice != null)
        {
            return;
        }

        if (stylusPoints == null)
        {
            return;
        }

        Point pt = e.GetPosition(this);
        stylusPoints.Add(new StylusPoint(pt.X, pt.Y));

        // Create a stroke and add it to the InkPresenter.
        Stroke stroke = new Stroke(stylusPoints);
        stroke.DrawingAttributes = dr.DrawingAttributes;
        ip.Strokes.Add(stroke);

        stylusPoints = null;

    }
}

追加のプラグインと DynamicRenderer の使用

InkCanvas と同様に、カスタム コントロールでも、カスタム StylusPlugIn オブジェクトや追加の DynamicRenderer オブジェクトを使用できます。これらのオブジェクトを StylusPlugIns コレクションに追加します。StylusPlugInCollection 内での StylusPlugIn オブジェクトの順番は、インクが描画されるときの外観に影響します。たとえば、dynamicRenderer という DynamicRenderer およびタブレット ペンのインクをオフセットする translatePlugin というカスタムの StylusPlugIn があるとします。translatePlugin が StylusPlugInCollection 内の最初の StylusPlugIn で、dynamicRenderer が 2 番目の場合、ユーザーがペンを動かすと、"流れる" インクがオフセットされます。dynamicRenderer が最初で、translatePlugin が 2 番目の場合、インクは、ユーザーがペンを持ち上げるまでオフセットされません。

まとめ

スタイラス イベント メソッドのオーバーライドにより、インクを収集してレンダリングするカスタム コントロールを作成できます。独自のコントロールを作成し、独自の StylusPlugIn クラスを派生させ、それらのクラスを StylusPlugInCollection に挿入することにより、デジタル インクで想定できるすべての動作を事実上実装できます。生成されたとおりの StylusPoint データにアクセスできるため、アプリケーションの必要に応じて Stylus 入力をカスタマイズし、画面上にレンダリングすることができるようになります。StylusPoint データにそのように低いレベルでアクセスできるため、インク コレクションの実装とアプリケーションに最適なパフォーマンスでのレンダリングを実現できます。

参照

その他の技術情報

高度なインク処理

Accessing and Manipulating Pen Input