建立筆墨輸入控制項

您可以建立動態和靜態呈現筆跡的自訂控制項。 也就是說,無論是透過手寫筆、從剪貼簿貼上,或是從檔案載入,可以在使用者繪製筆劃呈現,使筆跡從手寫筆「流出」,並在筆跡新增至控制項後顯示筆跡。 為了以動態方式呈現筆跡,控制項必須使用 DynamicRenderer。 若要以靜態方式呈現筆跡,您必須覆寫手寫筆事件方法 (OnStylusDownOnStylusMoveOnStylusUp),以收集 StylusPoint 資料、建立筆劃,並將其新增至 InkPresenter (轉譯為控制項上的筆跡)。

本主題包含下列子章節:

如何:收集手寫筆點資料並建立筆跡筆劃

若要建立可收集並管理筆跡筆劃的控制項,請執行下列動作:

  1. Control衍生類別,或衍生自Control的其中一個類別,例如Label

    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

    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. 藉由呼叫 AttachVisuals 方法,將 DynamicRendererRootVisual 附加至 InkPresenter,並將 DynamicRenderer 新增至 StylusPlugIns 集合。 這可讓 InkPresenter 在控制項收集手寫筆點資料時顯示筆跡。

    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來擷取手寫筆。 藉由擷取手寫筆,即使手寫筆離開控制項的界限,您的控制項仍會繼續接收 StylusMoveStylusUp 事件。 這不是強制性的,但若希望有良好的使用者體驗,仍建議使用。 建立新的 StylusPointCollection 來收集 StylusPoint 資料。 最後,將初始的一組 StylusPoint 資料新增至 StylusPointCollection

    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 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。 將您建立的新 Stroke 新增至 InkPresenter 和發行手寫筆擷取的 Strokes 集合。

    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 ,並將 StylusPoint 新增至 StylusPointCollection

    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 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 ,並將您建立的新 Stroke 新增至 InkPresenterStrokes集合。

    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;
    }
    

將它放在一起

下列範例是在使用者使用滑鼠或手寫筆時,收集筆跡的自訂控制項。

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;
    }
}

使用其他外掛程式和 DynamicRenderers

如同 InkCanvas,您的自訂控制項可以有自訂 StylusPlugIn 和其他 DynamicRenderer 物件。 將這些新增至 StylusPlugIns 集合。 在 StylusPlugInCollection 中,StylusPlugIn 物件的順序會影響轉譯時筆跡顯示的外觀。 假設您有名為 dynamicRendererDynamicRenderer,以及稱為 translatePlugin 的自訂 StylusPlugIn,會從平板電腦手寫筆中位移筆跡。 如果 translatePluginStylusPlugInCollection 中的第一個 StylusPlugIn,而 dynamicRenderer 是第二個,當使用者移動手寫筆時,「流出」的筆跡將會位移。 如果 dynamicRenderer 是第一個,且 translatePlugin 為第二個,則在手寫筆被使用者移開之前,筆跡將不會位移。

結論

您可以覆寫手寫筆事件方法,建立能收集和轉譯筆跡的控制項。 藉由建立自己的控制項、衍生自己的 StylusPlugIn 類別,並將其插入 StylusPlugInCollection,您幾乎可以實作任何想像得到的數位筆跡行為。 您可以存取產生的 StylusPoint 資料,就能夠自訂 Stylus 輸入,並視應用程式的情況在畫面上轉譯。 由於您對 StylusPoint 資料具有低層級存取權,因此您可以實作筆跡集合,並以應用程式的最佳效能轉譯。

另請參閱