Partager via


Création d’un contrôle d’entrée manuscrite

Vous pouvez créer un contrôle personnalisé qui rend l'encre de façon dynamique et statique. Autrement dit, faire apparaître l'encre à mesure qu'un utilisateur dessine un trait, ce qui donne l'impression que l'encre "coule" depuis le stylet de la tablette, et afficher l'encre après son ajout au composant de contrôle, que ce soit via le stylet de tablette, collée depuis le Presse-papiers ou chargée depuis un fichier. Pour afficher dynamiquement l'encre, votre contrôle doit utiliser un DynamicRenderer. Pour rendre statiquement l'encre, vous devez remplacer les méthodes d’événement de stylet (OnStylusDown, OnStylusMove et OnStylusUp) pour collecter les données de StylusPoint, créer des traits et les ajouter à un InkPresenter (qui rend l'encre 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érivez une classe à partir de Control, ou de l'une des classes dérivées de Control, comme Label par exemple.

    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 RootVisual de DynamicRenderer à InkPresenter en appelant la méthode AttachVisuals, et ajoutez l’DynamicRenderer à la collection StylusPlugIns. Cela permet au InkPresenter d'afficher l'encre à mesure que les données du point de stylet sont collectées par votre composant.

    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 composant continuera de recevoir les événements StylusMove et StylusUp même si le stylet sort des limites du composant. 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. Substituez la méthode OnStylusUp et créez une nouvelle Stroke en utilisant les données StylusPointCollection. Ajoutez le nouveau Stroke que vous avez créé à la collection Strokes de InkPresenter et libérez la capture du stylet.

    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. Outrepassez le OnMouseLeftButtonDown et créez un nouveau StylusPointCollection. Obtenez la position de la souris lorsque l’événement se produit et créez un StylusPoint à l’aide des données de point et ajoutez le 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 le StylusPoint à l'objet StylusPointCollection 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 données StylusPointCollection, et ajoutez le nouveau Stroke que vous avez créé à la collection Strokes 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;
    }
    

Mettez-le ensemble

L’exemple suivant est un contrôle personnalisé qui collecte de l'encre lorsque l’utilisateur utilise soit la souris, soit 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 modules d'extension et de moteurs de rendu dynamiques 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. Suppose vous avez un DynamicRenderer appelé dynamicRenderer et un StylusPlugIn personnalisé appelé translatePlugin qui décale l’encre du stylet de la tablette. S’il translatePlugin s’agit du premier StylusPlugIn dans le StylusPlugInCollection, et que dynamicRenderer est le deuxième, l’encre qui « coule » sera décalée lorsque l’utilisateur déplace le stylet. Si dynamicRenderer est le premier, et translatePlugin est le second, l'encre ne sera pas déplacée tant que l'utilisateur ne lève pas le stylet.

Conclusion

Vous pouvez créer un contrôle qui collecte et affiche de l'encre numérique 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 dans le StylusPlugInCollection, vous 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 collecte d'encre et les restituer avec des performances optimales pour votre application.

Voir aussi