Share via


Inkt voor aangepaste rendering

Met de eigenschap DrawingAttributes van een lijn kunt u het uiterlijk van een lijn definiëren, zoals de grootte, kleur en vorm, maar soms wilt u het uiterlijk verder aanpassen dan wat DrawingAttributes toestaan. U kunt het uiterlijk van inkt aanpassen door het uiterlijk van een luchtborstel, olieverf en vele andere effecten aan te passen. Met WpF (Windows Presentation Foundation) kunt u inkt op maat weergeven door een aangepast DynamicRenderer- en Stroke-object te implementeren.

Dit onderwerp bevat de volgende subsecties:

Architectuur

Inktweergave vindt twee keer plaats; wanneer een gebruiker inkt naar een inktoppervlak schrijft en opnieuw nadat de pennenstreek is toegevoegd aan het oppervlak met inkt. De DynamicRenderer geeft de inkt weer wanneer de gebruiker de tabletpen op de digitaler verplaatst en de Stroke zichzelf weergeeft zodra deze aan een element is toegevoegd.

Er zijn drie klassen die moeten worden geïmplementeerd wanneer inkt dynamisch wordt weergegeven.

  1. DynamicRenderer-: implementeer een klasse die is afgeleid van DynamicRenderer. Deze klasse is een gespecialiseerde StylusPlugIn die de lijn weergeeft terwijl deze wordt getekend. De DynamicRenderer voert de rendering uit op een afzonderlijke thread, dus lijkt het inktoppervlak inkt te verzamelen, zelfs wanneer de gebruikersinterface-thread van de toepassing wordt geblokkeerd. Voor meer informatie over het threadingmodel, zie The Ink Threading Model. Om het dynamisch renderen van een pennenstreek aan te passen, overschrijft u de methode OnDraw.

  2. Stroke: implementeer een class die is afgeleid van Stroke. Deze klasse is verantwoordelijk voor statische rendering van de StylusPoint gegevens nadat deze zijn geconverteerd naar een Stroke-object. Overschrijf de methode DrawCore om ervoor te zorgen dat statische rendering van de lijn consistent is met dynamische rendering.

  3. InkCanvas: Een klasse implementeren die is afgeleid van InkCanvas. Wijs de aangepaste DynamicRenderer toe aan de eigenschap DynamicRenderer. Overschrijf de methode OnStrokeCollected en voeg een aangepaste lijn toe aan de eigenschap Strokes. Dit zorgt ervoor dat het uiterlijk van de inkt consistent is.

Een dynamische renderer implementeren

Hoewel de DynamicRenderer-klasse een standaardonderdeel is van WPF, moet u een aangepaste dynamische weergave-eenheid maken die afstamt van de DynamicRenderer en de OnDraw-methode overschrijft.

In het volgende voorbeeld ziet u een aangepaste DynamicRenderer die inktstrepen zet met een lineair verlooppenseeleffect.

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

Aangepaste pennenstreken implementeren

Implementeer een klasse die is afgeleid van Stroke. Deze klasse is verantwoordelijk voor het weergeven van StylusPoint gegevens nadat deze zijn geconverteerd naar een Stroke-object. Overschrijf de DrawCore klasse om de werkelijke tekening uit te voeren.

Uw Stroke-klasse kan ook aangepaste gegevens opslaan met behulp van de methode AddPropertyData. Deze gegevens worden opgeslagen met de pennenstreekgegevens wanneer deze behouden blijven.

De Stroke-klasse kan ook hittests uitvoeren. U kunt ook uw eigen algoritme voor het testen van treffers implementeren door de HitTest methode in de huidige klasse te overschrijven.

De volgende C#-code demonstreert een aangepaste Stroke klasse die StylusPoint gegevens weergeeft als een 3D-pennenstreek.

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

Een aangepaste InkCanvas implementeren

De eenvoudigste manier om uw aangepaste DynamicRenderer en lijnen te gebruiken, is door een klasse te implementeren die is afgeleid van InkCanvas en deze gebruikt. De InkCanvas heeft een eigenschap DynamicRenderer die aangeeft hoe de pennenstreek wordt weergegeven wanneer de gebruiker deze tekent.

Ga als volgt te werk om aangepaste lijnen te renderen op een InkCanvas:

De volgende C#-code demonstreert een aangepaste InkCanvas-klasse die gebruikmaakt van een aangepaste DynamicRenderer en aangepaste pennenstreken verzamelt.

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

Een InkCanvas kan meer dan één DynamicRendererhebben. U kunt meerdere DynamicRenderer objecten toevoegen aan de InkCanvas door ze toe te voegen aan de eigenschap StylusPlugIns.

Conclusie

U kunt het uiterlijk van inkt aanpassen door uw eigen DynamicRenderer, Strokeen InkCanvas klassen af te leiden. Samen zorgen deze klassen ervoor dat het uiterlijk van de penseelstreek consistent is wanneer de gebruiker de penseelstreek tekent en nadat deze is verzameld.

Zie ook