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 manière dynamique et statique. Autrement dit, afficher l'encre au fur et à mesure qu'un utilisateur dessine un trait, faisant ainsi apparaître l'encre comme si elle "coulait" à partir du stylet de tablette, et afficher l’encre après son ajout à l’élément de commande, soit via le stylet de tablette, soit collée à partir du Presse-papiers, ou chargée à partir d’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, OnStylusMoveet OnStylusUp) pour collecter les données 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 de Control ou l’une des classes dérivées de Control, comme 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. Ajoutez un InkPresenter à la classe et définissez la propriété Content sur la nouvelle InkPresenter.

    InkPresenter ip;
    
    public InkControl()
    {
        // Add an InkPresenter for drawing.
        ip = new InkPresenter();
        this.Content = ip;
    }
    
  3. Attachez la RootVisual du DynamicRenderer au InkPresenter en appelant la méthode AttachVisuals, puis ajoutez le DynamicRenderer à la collection StylusPlugIns. Cela permet à l'InkPresenter d'afficher l'encre car les données du stylet sont collectées par votre dispositif.

    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, saisissez le stylet avec un appel à Capture. En capturant le stylet, votre contrôle continuera à recevoir des événements StylusMove et StylusUp 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 une nouvelle StylusPointCollection afin de collecter des données StylusPoint. Enfin, ajoutez l’ensemble initial de données StylusPoint 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 méthode OnStylusMove et ajoutez les données StylusPoint à 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 méthode OnStylusUp et créez une Stroke avec les données StylusPointCollection. Ajoutez la nouvelle Stroke que vous avez créée à 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 employez la souris comme dispositif de saisie, vous remarquerez que les traits ne sont pas conservés. Pour maintenir les traits lorsque la souris est utilisée comme dispositif de saisie, suivez ces étapes :

  1. Remplacez le OnMouseLeftButtonDown et créez une nouvelle StylusPointCollection Obtenir la position de la souris lorsque l’événement s’est produit et créez un StylusPoint à l’aide des données de point et ajoutez le StylusPoint au 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 un 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 Stroke avec les données de StylusPointCollection et ajoutez la nouvelle Stroke que vous avez créée à 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 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 de DynamicRenderers supplémentaires

Comme l'InkCanvas, votre contrôle personnalisé peut avoir des StylusPlugIn personnalisés et des objets DynamicRenderer supplémentaires. Ajoutez-les à la collection StylusPlugIns. L’ordre des objets StylusPlugIn dans la StylusPlugInCollection affecte l’apparence de l’encre lorsqu’elle est appliquée. Supposons que vous ayez un DynamicRenderer appelé dynamicRenderer et un StylusPlugIn personnalisé appelé translatePlugin qui décale l’encre du stylet de la tablette. Si translatePlugin est la première StylusPlugIn dans l'StylusPlugInCollectionet dynamicRenderer est la deuxième, l’encre qui coule sera décalée lorsque l’utilisateur déplace le stylet. Si dynamicRenderer est en premier, et que translatePlugin est en deuxième position, l'encre ne sera pas décalée tant que l'utilisateur n'aura pas levé le stylet.

Conclusion

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

Voir aussi