Création d'un contrôle d'entrée d'encre

Vous pouvez créer un contrôle personnalisé qui affiche dynamiquement et statiquement des entrées manuscrites. Autrement dit, le rendu de l’encre en tant qu’utilisateur dessine un trait, ce qui entraîne l’affichage de l’encre à partir du stylet de tablette et l’affichage de l’encre après son ajout au contrôle, via le stylet de tablette, collé à partir du Presse-papiers ou chargé à partir d’un fichier. Pour afficher dynamiquement l’entrée manuscrite, votre contrôle doit utiliser un DynamicRenderer. Pour afficher statiquement les entrées manuscrites, vous devez remplacer les méthodes d’événement de stylet (OnStylusDown, OnStylusMoveet OnStylusUp) pour collecter StylusPoint des données, créer des traits et les ajouter à un InkPresenter (qui affiche l’entrée manuscrite sur le contrôle).

Cette rubrique contient les sous-sections suivantes :

Guide pratique pour collecter des données de point de stylet et créer des traits d’encre

Pour créer un contrôle qui collecte et gère les traits d’encre, procédez comme suit :

  1. Dériver une classe de Control ou l’une des classes dérivées Controlde , par Labelexemple .

    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. Ajoutez une InkPresenter à la classe et définissez la Content propriété sur la nouvelle InkPresenter.

    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. Attachez l’élément RootVisualDynamicRenderer à la InkPresenter méthode en appelant la AttachVisuals méthode et ajoutez-le DynamicRenderer à la StylusPlugIns collection. Cela permet d’afficher l’encre InkPresenter en tant que données de point de stylet collectées par votre contrôle.

    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. Remplacez la méthode OnStylusDown . Dans cette méthode, capturez le stylet avec un appel à Capture. En capturant le stylet, votre contrôle continuera de recevoir StylusMove et StylusUp d’événements même si le stylet quitte les limites du contrôle. Ce n’est pas strictement obligatoire, mais presque toujours souhaité pour une bonne expérience utilisateur. Créez un nouveau StylusPointCollection pour collecter des StylusPoint données. Enfin, ajoutez le jeu initial de StylusPoint données au 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. Remplacez la OnStylusMove méthode et ajoutez les StylusPoint données à l’objet StylusPointCollection que vous avez créé précédemment.

    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. Remplacez la OnStylusUp méthode et créez-en une Stroke avec les StylusPointCollection données. Ajoutez le nouveau Stroke que vous avez créé à la Strokes collection de la InkPresenter capture de stylet de mise en production et de mise en production.

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

Procédure : activer votre contrôle pour accepter l’entrée à partir de la souris

Si vous ajoutez le contrôle précédent à votre application, exécutez-le et utilisez la souris comme appareil d’entrée, vous remarquerez que les traits ne sont pas conservés. Pour conserver les traits lorsque la souris est utilisée comme périphérique d’entrée, procédez comme suit :

  1. Remplacez et OnMouseLeftButtonDown créez une StylusPointCollection nouvelle position Obtenir la position de la souris lorsque l’événement s’est produit et créez-en une StylusPoint à l’aide des données de point et ajoutez-les StylusPoint à l’élément 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. Remplacez la méthode OnMouseMove . Obtenez la position de la souris lorsque l’événement s’est produit et créez-en une StylusPoint à l’aide des données de point. Ajoutez l’objet StylusPointStylusPointCollection que vous avez créé précédemment.

    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. Remplacez la méthode OnMouseLeftButtonUp . Créez un nouveau Stroke avec les StylusPointCollection données et ajoutez le nouveau Stroke que vous avez créé à la Strokes collection du 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;
    }
    

Synthèse

L’exemple suivant est un contrôle personnalisé qui collecte des entrées manuscrites lorsque l’utilisateur utilise la souris ou le stylet.

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

Utilisation de plug-ins et dynamicRenderers supplémentaires

Comme InkCanvas, votre contrôle personnalisé peut avoir des objets personnalisés StylusPlugIn et supplémentaires DynamicRenderer . Ajoutez-les à la StylusPlugIns collection. L’ordre des StylusPlugIn objets dans l’objet StylusPlugInCollection affecte l’apparence de l’encre lorsqu’il est rendu. Supposons que vous avez un DynamicRenderer appel dynamicRenderer et un appelé translatePlugin personnalisé StylusPlugIn qui décalera l’encre du stylet de tablette. S’il translatePlugin s’agit du premier StylusPlugIn dans le StylusPlugInCollection, et dynamicRenderer est le deuxième, l’encre qui « flux » sera décalée lorsque l’utilisateur déplace le stylet. Si dynamicRenderer elle est d’abord, et translatePlugin est seconde, l’entrée manuscrite ne sera pas décalée tant que l’utilisateur ne lève pas le stylet.

Conclusion

Vous pouvez créer un contrôle qui collecte et affiche des entrées manuscrites en remplaçant les méthodes d’événement de stylet. En créant votre propre contrôle, en dérivant vos propres StylusPlugIn classes et en les insérant, StylusPlugInCollectionvous pouvez implémenter pratiquement n’importe quel comportement imaginable avec l’encre numérique. Vous avez accès aux StylusPoint données au fur et à mesure qu’elles sont générées, ce qui vous donne la possibilité de personnaliser Stylus l’entrée et de l’afficher à l’écran selon les besoins de votre application. Étant donné que vous disposez d’un tel accès de bas niveau aux StylusPoint données, vous pouvez implémenter la collection d’entrées manuscrites et la restituer avec des performances optimales pour votre application.

Voir aussi