Skapa en bläck-indatakontroll

Du kan skapa en anpassad kontroll som dynamiskt och statiskt visar bläck. Det innebär att rendera bläck när en användare ritar ett slag, vilket får det att se ut som att bläcket "flödar" från surfplattans penna, och visa bläcket när det har lagts till i kontrollen, antingen via surfplattans penna, klistrat in från Urklipp eller inläst från en fil. Om du vill återge pennanteckningar dynamiskt måste kontrollen använda en DynamicRenderer. Om du vill återge pennanteckningar statiskt måste du åsidosätta pennans händelsemetoder (OnStylusDown, OnStylusMoveoch OnStylusUp) för att samla in StylusPoint data, skapa linjer och lägga till dem i en InkPresenter (som återger pennanteckningen på kontrollen).

Det här avsnittet innehåller följande underavsnitt:

Gör så här: Samla in pennans punktdata och skapa pennstreck

Så här skapar du en kontroll som samlar in och hanterar pennstreck:

  1. Härled en klass från Control eller någon av klasserna som härleds från Control, till exempel 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. Lägg till en InkPresenter i klassen och ange egenskapen Content till den nya InkPresenter.

    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. Koppla RootVisual för DynamicRenderer till InkPresenter genom att anropa metoden AttachVisuals och lägga till DynamicRenderer i samlingen StylusPlugIns. På så sätt kan InkPresenter visa pennanteckningen när pennans punktdata samlas in av din kontroll.

    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. Åsidosätt metoden OnStylusDown. I den här metoden fångar du upp stylusen med ett anrop till Capture. Genom att fånga upp pennan kommer din kontroll att fortsätta ta emot StylusMove och StylusUp händelser även om pennan lämnar kontrollens gränser. Detta är inte strikt obligatoriskt, men nästan alltid önskat för en bra användarupplevelse. Skapa en ny StylusPointCollection för att samla in StylusPoint data. Lägg slutligen till den första uppsättningen av StylusPoint-data i 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. Åsidosätt metoden OnStylusMove och lägg till StylusPoint data i det StylusPointCollection objekt som du skapade tidigare.

    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. Åsidosätt metoden OnStylusUp och skapa en ny Stroke med StylusPointCollection data. Lägg till den nya Stroke du skapade i Strokes-samlingen av InkPresenter och släpp stylusfångsten.

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

Gör så här: Aktivera din kontroll för att acceptera indata från musen

Om du lägger till den tidigare nämnda kontrollen i ditt program, kör det och använder musen, kommer du att märka att strecken inte sparas. Så här bevarar du strecken när musen används som indataenhet:

  1. Åsidosätt OnMouseLeftButtonDown och skapa en ny StylusPointCollection Hämta muspositionen när händelsen inträffade och skapa en StylusPoint med hjälp av punktdata och lägg till StylusPoint i 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. Åsidosätt metoden OnMouseMove. Hämta musens position när händelsen inträffade och skapa en StylusPoint med hjälp av punktdata. Lägg till StylusPoint i det StylusPointCollection objekt som du skapade tidigare.

    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. Åsidosätt metoden OnMouseLeftButtonUp. Skapa en ny Stroke med StylusPointCollection-datan och lägg till den nya Stroke som du skapade i Strokes-samlingen av InkPresenter.

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

Sätta ihop det

Följande exempel är en anpassad kontroll som samlar in pennanteckningar när användaren använder musen eller pennan.

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

Använda ytterligare plugin-program och DynamicRenderers

Precis som InkCanvas kan din anpassade kontroll ha anpassade StylusPlugIn och ytterligare DynamicRenderer objekt. Lägg till dessa i samlingen StylusPlugIns. Ordningen av StylusPlugIn-objekt i StylusPlugInCollection påverkar utseendet på bläcket när det återges. Anta att du har en DynamicRenderer kallad dynamicRenderer och en anpassad StylusPlugIn kallad translatePlugin som förskjuter bläcket från ritplattans penna. Om translatePlugin är den första StylusPlugIn i StylusPlugInCollectionoch dynamicRenderer är den andra, kommer bläcket som "flödar" att förskjutas när användaren flyttar pennan. Om dynamicRenderer är först och translatePlugin är tvåa kommer bläcket inte att förskjutas förrän användaren lyfter pennan.

Slutsats

Du kan skapa en kontroll som samlar in och renderar pennanteckningar genom att åsidosätta stylushändelsemetoderna. Genom att skapa din egen kontroll, härleda dina egna StylusPlugIn klasser och infoga dem i StylusPlugInCollectionkan du implementera praktiskt taget alla beteenden som kan tänkas med digital pennanteckning. Du har åtkomst till StylusPoint data när de genereras, vilket ger dig möjlighet att anpassa Stylus indata och återge dem på skärmen efter behov för ditt program. Eftersom du har sådan åtkomst på låg nivå till StylusPoint data kan du implementera insamling av bläck och rendera det med den optimala prestandan för din applikation.

Se även