Tworzenie formantu danych wejściowych atramentu

Można utworzyć kontrolkę niestandardową, która dynamicznie i statycznie renderuje atrament. Oznacza to, że renderowanie pisma odręcznego w przypadku, gdy użytkownik naciągnie pociągnięcie, co powoduje "przepływ" pisma odręcznego z pióra tabletu i wyświetlenie pisma odręcznego po dodaniu go do kontrolki za pośrednictwem pióra tabletu, wklejonych ze schowka lub załadowanych z pliku. Aby dynamicznie renderować atrament, kontrolka musi używać kontrolki DynamicRenderer. Aby statycznie renderować atrament, należy zastąpić metody zdarzeń pisaka (OnStylusDown, OnStylusMovei OnStylusUp) StylusPoint w celu zbierania danych, InkPresenter tworzenia pociągnięć i dodawania ich do kontrolki (która renderuje atrament w kontrolce).

Ten temat zawiera następujące podsekcji:

How to: Collect Stylus Point Data and Create Ink Strokes

Aby utworzyć kontrolkę, która zbiera pociągnięcia pisma odręcznego i zarządza nimi, wykonaj następujące czynności:

  1. Wyprowadzenie klasy z Control klasy lub jednej z klas pochodzących z Controlklasy , takiej jak 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. Dodaj element InkPresenter do klasy i ustaw właściwość Content na nową wartość InkPresenter.

    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. Dołącz do RootVisual metody DynamicRenderer , InkPresenter wywołując AttachVisuals metodę i dodaj do DynamicRenderer kolekcji StylusPlugIns . Dzięki temu kontrolka InkPresenter może wyświetlać atrament, gdy dane punktu pióra są zbierane przez kontrolkę.

    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. Zastąp metodę OnStylusDown . W tej metodzie przechwyć pisak za pomocą wywołania metody Capture. Przechwytując pisak, kontrolka będzie nadal odbierać zdarzenia i nawet wtedy, StylusMoveStylusUp gdy pisak opuści granice kontrolki. Nie jest to bezwzględnie obowiązkowe, ale prawie zawsze pożądane w celu uzyskania dobrego doświadczenia użytkownika. Utwórz nową platformę StylusPointCollection do zbierania StylusPoint danych. Na koniec dodaj początkowy zestaw danych StylusPoint do .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. Zastąp metodę OnStylusMove i dodaj StylusPoint dane do utworzonego StylusPointCollection wcześniej obiektu .

    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. Zastąp metodę OnStylusUp i utwórz nową z Stroke danymi StylusPointCollection . Dodaj nowo utworzony Stroke obraz do kolekcji StrokesInkPresenter przechwytywania pisaka i wydania.

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

Jak włączyć kontrolkę akceptować dane wejściowe z myszy

Jeśli dodasz poprzednią kontrolkę do aplikacji, uruchom ją i użyjemy myszy jako urządzenia wejściowego, zauważysz, że pociągnięcia nie są utrwalane. Aby utrwalić pociągnięcia, gdy mysz jest używana jako urządzenie wejściowe, wykonaj następujące czynności:

  1. Zastąp i OnMouseLeftButtonDown utwórz nową StylusPointCollection pozycję Pobierz pozycję myszy w momencie wystąpienia zdarzenia, a StylusPoint następnie utwórz za pomocą danych punktu i dodaj StylusPoint do .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. Zastąp metodę OnMouseMove . Pobierz pozycję myszy w momencie wystąpienia zdarzenia i utwórz za pomocą StylusPoint danych punktu. Dodaj obiekt StylusPoint do StylusPointCollection utworzonego wcześniej obiektu .

    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. Zastąp metodę OnMouseLeftButtonUp . Utwórz nową Stroke z danymi StylusPointCollection i dodaj Stroke nowo utworzony do kolekcji Strokes .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;
    }
    

Umieszczanie go razem

Poniższy przykład to kontrolka niestandardowa, która zbiera atrament, gdy użytkownik używa myszy lub pióra.

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

Korzystanie z dodatkowych wtyczek i dynamicRenderers

Podobnie jak kontrolka InkCanvas, kontrolka niestandardowa może mieć niestandardowe StylusPlugIn i dodatkowe DynamicRenderer obiekty. Dodaj je do kolekcji StylusPlugIns . Kolejność obiektów StylusPlugIn w obiektach StylusPlugInCollection wpływa na wygląd pisma odręcznego podczas renderowania. Załóżmy, że masz DynamicRenderer nazwę i dynamicRenderer niestandardowy o StylusPlugIn nazwie translatePlugin , który odsunie atrament od pióra tabletu. Jeśli translatePlugin jest pierwszy w StylusPlugInStylusPlugInCollection, i dynamicRenderer jest drugi, pisma odręcznego, który "przepływy" zostanie przesunięte, gdy użytkownik przenosi piórem. Jeśli dynamicRenderer jest pierwszy, a drugi translatePlugin , atrament nie zostanie przesunięty, dopóki użytkownik nie podniesie pióra.

Podsumowanie

Możesz utworzyć kontrolkę, która zbiera i renderuje atrament, przesłaniając metody zdarzeń pisaka. Tworząc własną kontrolę, StylusPlugInStylusPlugInCollectionwyprowadzając własne klasy i wstawiając je do klasy , możesz zaimplementować praktycznie dowolne zachowanie, które można sobie wyobrazić za pomocą cyfrowego pisma odręcznego. Masz dostęp do danych StylusPoint podczas ich generowania, Stylus co daje możliwość dostosowania danych wejściowych i renderowania ich na ekranie zgodnie z potrzebami aplikacji. Ponieważ masz tak niski dostęp StylusPoint do danych, możesz zaimplementować zbieranie pisma odręcznego i renderować je z optymalną wydajnością dla aplikacji.

Zobacz też