Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
La propriété DrawingAttributes d’un trait vous permet de spécifier l’apparence d’un trait, comme sa taille, sa couleur et sa forme, mais il peut y avoir des moments où vous souhaitez personnaliser l’apparence au-delà de ce que DrawingAttributes autoriser. Vous pouvez personnaliser l’apparence de l’encre pour lui donner l’aspect d’un aérographe, d'une peinture à l’huile et de nombreux autres effets. La Windows Presentation Foundation (WPF) vous permet d'effectuer un rendu personnalisé de l'encre en implémentant des objets personnalisés DynamicRenderer et Stroke.
Cette rubrique contient les sous-sections suivantes :
Architecture
Le rendu de l'encre se produit deux fois : lorsqu'un utilisateur écrit de l'encre sur une surface d'encrage, puis une fois que le trait est ajouté à la surface compatible avec l'encre. Le DynamicRenderer restitue l’encre lorsque l’utilisateur déplace le stylet de tablette sur le numériseur, et le Stroke s’affiche une fois qu’il est ajouté à un élément.
Il existe trois classes à implémenter lors du rendu dynamique de l’encre.
DynamicRenderer: implémentez une classe qui dérive de DynamicRenderer. Cette classe est une StylusPlugIn spécialisée qui restitue le trait tel qu’il est dessiné. L'DynamicRenderer effectue le rendu sur un thread distinct, de sorte que la surface d'encrage semble collecter de l'encre même lorsque le thread d’interface utilisateur de l’application est bloqué. Pour plus d’informations sur le modèle de thread, consultez Modèle de thread de l’encre. Pour personnaliser le rendu dynamique d’un trait, remplacez la méthode OnDraw.
Trait : implémentez une classe qui dérive de Stroke. Cette classe est responsable du rendu statique des données StylusPoint une fois qu’elles ont été converties en objet Stroke. Remplacez la méthode DrawCore pour vous assurer que le rendu statique du trait est cohérent avec le rendu dynamique.
InkCanvas : Implémenter une classe qui dérive de InkCanvas. Affectez le DynamicRenderer personnalisé à la propriété DynamicRenderer. Remplacez la méthode OnStrokeCollected et ajoutez un trait personnalisé à la propriété Strokes. Cela garantit que l’apparence de l’encre est cohérente.
Implémentation d’un renderer dynamique
Bien que la classe DynamicRenderer soit une partie standard de WPF, pour effectuer un rendu plus spécialisé, vous devez créer un renderer dynamique personnalisé qui dérive de la DynamicRenderer et remplacer la méthode OnDraw.
L’exemple suivant illustre un DynamicRenderer personnalisé qui dessine l’encre avec un effet de pinceau de dégradé linéaire.
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;
Imports System.Windows.Media
Imports System.Windows
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Input
Imports System.Windows.Ink
// A StylusPlugin that renders ink with a linear gradient brush effect.
class CustomDynamicRenderer : DynamicRenderer
{
[ThreadStatic]
static private Brush brush = null;
[ThreadStatic]
static private Pen pen = null;
private Point prevPoint;
protected override void OnStylusDown(RawStylusInput rawStylusInput)
{
// Allocate memory to store the previous point to draw from.
prevPoint = new Point(double.NegativeInfinity, double.NegativeInfinity);
base.OnStylusDown(rawStylusInput);
}
protected override void OnDraw(DrawingContext drawingContext,
StylusPointCollection stylusPoints,
Geometry geometry, Brush fillBrush)
{
// Create a new Brush, if necessary.
brush ??= new LinearGradientBrush(Colors.Red, Colors.Blue, 20d);
// Create a new Pen, if necessary.
pen ??= new Pen(brush, 2d);
// Draw linear gradient ellipses between
// all the StylusPoints that have come in.
for (int i = 0; i < stylusPoints.Count; i++)
{
Point pt = (Point)stylusPoints[i];
Vector v = Point.Subtract(prevPoint, pt);
// Only draw if we are at least 4 units away
// from the end of the last ellipse. Otherwise,
// we're just redrawing and wasting cycles.
if (v.Length > 4)
{
// Set the thickness of the stroke based
// on how hard the user pressed.
double radius = stylusPoints[i].PressureFactor * 10d;
drawingContext.DrawEllipse(brush, pen, pt, radius, radius);
prevPoint = pt;
}
}
}
}
' A StylusPlugin that renders ink with a linear gradient brush effect.
Class CustomDynamicRenderer
Inherits DynamicRenderer
<ThreadStatic()> _
Private Shared brush As Brush = Nothing
<ThreadStatic()> _
Private Shared pen As Pen = Nothing
Private prevPoint As Point
Protected Overrides Sub OnStylusDown(ByVal rawStylusInput As RawStylusInput)
' Allocate memory to store the previous point to draw from.
prevPoint = New Point(Double.NegativeInfinity, Double.NegativeInfinity)
MyBase.OnStylusDown(rawStylusInput)
End Sub
Protected Overrides Sub OnDraw(ByVal drawingContext As DrawingContext, _
ByVal stylusPoints As StylusPointCollection, _
ByVal geometry As Geometry, _
ByVal fillBrush As Brush)
' Create a new Brush, if necessary.
If brush Is Nothing Then
brush = New LinearGradientBrush(Colors.Red, Colors.Blue, 20.0)
End If
' Create a new Pen, if necessary.
If pen Is Nothing Then
pen = New Pen(brush, 2.0)
End If
' Draw linear gradient ellipses between
' all the StylusPoints that have come in.
Dim i As Integer
For i = 0 To stylusPoints.Count - 1
Dim pt As Point = CType(stylusPoints(i), Point)
Dim v As Vector = Point.Subtract(prevPoint, pt)
' Only draw if we are at least 4 units away
' from the end of the last ellipse. Otherwise,
' we're just redrawing and wasting cycles.
If v.Length > 4 Then
' Set the thickness of the stroke based
' on how hard the user pressed.
Dim radius As Double = stylusPoints(i).PressureFactor * 10.0
drawingContext.DrawEllipse(brush, pen, pt, radius, radius)
prevPoint = pt
End If
Next i
End Sub
End Class
Implémentation de traits personnalisés
Implémentez une classe qui dérive de Stroke. Cette classe est responsable du rendu des données StylusPoint une fois qu’elles ont été converties en objet Stroke. Remplacez la classe DrawCore pour effectuer le dessin réel.
Votre classe Stroke peut également stocker des données personnalisées à l’aide de la méthode AddPropertyData. Ces données sont stockées avec les données du trait quand elles sont rendues persistantes.
La classe Stroke peut également effectuer des tests de collision. Vous pouvez également implémenter votre propre algorithme de test d'impact en remplaçant la méthode HitTest de la classe actuelle.
Le code C# suivant illustre une classe de Stroke personnalisée qui affiche StylusPoint données sous la forme d’un trait 3D.
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using System.Windows.Ink;
Imports System.Windows.Media
Imports System.Windows
Imports System.Windows.Input.StylusPlugIns
Imports System.Windows.Input
Imports System.Windows.Ink
// A class for rendering custom strokes
class CustomStroke : Stroke
{
Brush brush;
Pen pen;
public CustomStroke(StylusPointCollection stylusPoints)
: base(stylusPoints)
{
// Create the Brush and Pen used for drawing.
brush = new LinearGradientBrush(Colors.Red, Colors.Blue, 20d);
pen = new Pen(brush, 2d);
}
protected override void DrawCore(DrawingContext drawingContext,
DrawingAttributes drawingAttributes)
{
// Allocate memory to store the previous point to draw from.
Point prevPoint = new Point(double.NegativeInfinity,
double.NegativeInfinity);
// Draw linear gradient ellipses between
// all the StylusPoints in the Stroke.
for (int i = 0; i < this.StylusPoints.Count; i++)
{
Point pt = (Point)this.StylusPoints[i];
Vector v = Point.Subtract(prevPoint, pt);
// Only draw if we are at least 4 units away
// from the end of the last ellipse. Otherwise,
// we're just redrawing and wasting cycles.
if (v.Length > 4)
{
// Set the thickness of the stroke
// based on how hard the user pressed.
double radius = this.StylusPoints[i].PressureFactor * 10d;
drawingContext.DrawEllipse(brush, pen, pt, radius, radius);
prevPoint = pt;
}
}
}
}
' A class for rendering custom strokes
Class CustomStroke
Inherits Stroke
Private brush As Brush
Private pen As Pen
Public Sub New(ByVal stylusPoints As StylusPointCollection)
MyBase.New(stylusPoints)
' Create the Brush and Pen used for drawing.
brush = New LinearGradientBrush(Colors.Red, Colors.Blue, 20.0)
pen = New Pen(brush, 2.0)
End Sub
Protected Overrides Sub DrawCore(ByVal drawingContext As DrawingContext, _
ByVal drawingAttributes As DrawingAttributes)
' Allocate memory to store the previous point to draw from.
Dim prevPoint As New Point(Double.NegativeInfinity, Double.NegativeInfinity)
' Draw linear gradient ellipses between
' all the StylusPoints in the Stroke.
Dim i As Integer
For i = 0 To Me.StylusPoints.Count - 1
Dim pt As Point = CType(Me.StylusPoints(i), Point)
Dim v As Vector = Point.Subtract(prevPoint, pt)
' Only draw if we are at least 4 units away
' from the end of the last ellipse. Otherwise,
' we're just redrawing and wasting cycles.
If v.Length > 4 Then
' Set the thickness of the stroke
' based on how hard the user pressed.
Dim radius As Double = Me.StylusPoints(i).PressureFactor * 10.0
drawingContext.DrawEllipse(brush, pen, pt, radius, radius)
prevPoint = pt
End If
Next i
End Sub
End Class
Implémentation d’un InkCanvas personnalisé
La manière la plus simple d’utiliser votre DynamicRenderer et votre trait personnalisés consiste à implémenter une classe qui dérive de InkCanvas et utilise ces classes. Le InkCanvas a une propriété DynamicRenderer qui spécifie le rendu du trait lorsque l’utilisateur le dessine.
Pour personnaliser les traits de rendu sur un InkCanvas procédez comme suit :
Créez une classe qui dérive de la InkCanvas.
Affectez votre DynamicRenderer personnalisé à la propriété InkCanvas.DynamicRenderer.
Remplacez la méthode OnStrokeCollected. Dans cette méthode, supprimez le trait d’origine ajouté à InkCanvas. Créez ensuite un trait personnalisé, ajoutez-le à la propriété Strokes et appelez la classe de base avec une nouvelle InkCanvasStrokeCollectedEventArgs qui contient le trait personnalisé.
Le code C# suivant illustre une classe de InkCanvas personnalisée qui utilise un DynamicRenderer personnalisé et collecte des traits personnalisés.
public class CustomRenderingInkCanvas : InkCanvas
{
CustomDynamicRenderer customRenderer = new CustomDynamicRenderer();
public CustomRenderingInkCanvas() : base()
{
// Use the custom dynamic renderer on the
// custom InkCanvas.
this.DynamicRenderer = customRenderer;
}
protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e)
{
// Remove the original stroke and add a custom stroke.
this.Strokes.Remove(e.Stroke);
CustomStroke customStroke = new CustomStroke(e.Stroke.StylusPoints);
this.Strokes.Add(customStroke);
// Pass the custom stroke to base class' OnStrokeCollected method.
InkCanvasStrokeCollectedEventArgs args =
new InkCanvasStrokeCollectedEventArgs(customStroke);
base.OnStrokeCollected(args);
}
}
Un InkCanvas peut avoir plusieurs DynamicRenderer. Vous pouvez ajouter plusieurs objets DynamicRenderer au InkCanvas en les ajoutant à la propriété StylusPlugIns.
Conclusion
Vous pouvez personnaliser l’apparence de l’encre en dérivant vos propres classes DynamicRenderer, Strokeet InkCanvas. Ensemble, ces classes garantissent que l’apparence du trait est cohérente quand l’utilisateur dessine le trait et après qu’il a été collecté.
Voir aussi
.NET Desktop feedback