Bagikan melalui


Tinta Penyajian Kustom

Properti DrawingAttributes stroke memungkinkan Anda menentukan tampilan goresan, seperti ukuran, warna, dan bentuknya, tetapi mungkin ada kalanya Anda ingin menyesuaikan penampilan di luar apa yang DrawingAttributes memungkinkan. Anda mungkin ingin menyesuaikan penampilan tinta dengan merender dalam penampilan kuas udara, cat minyak, dan banyak efek lainnya. Windows Presentation Foundation (WPF) memungkinkan Anda untuk merender tinta kustom dengan menerapkan kustom DynamicRenderer dan Stroke objek.

Topik ini berisi sub bagian berikut:

Arsitektur

Penyajian tinta terjadi dua kali; ketika pengguna menulis tinta ke permukaan penintaan, dan sekali lagi setelah goresan ditambahkan ke permukaan yang diaktifkan tinta. Merender DynamicRenderer tinta ketika pengguna memindahkan pena tablet pada digitizer, dan Stroke merendernya sendiri setelah ditambahkan ke elemen.

Ada tiga kelas yang akan diterapkan saat merender tinta secara dinamis.

  1. DynamicRenderer: Menerapkan kelas yang berasal dari DynamicRenderer. Kelas ini adalah spesialisasi StylusPlugIn yang merender goresan seperti yang digambar. DynamicRenderer apakah penyajian pada utas terpisah, sehingga permukaan penintaan tampaknya mengumpulkan tinta bahkan ketika utas antarmuka pengguna aplikasi (UI) diblokir. Untuk informasi selengkapnya tentang model utas, lihat Model Utas Tinta. Untuk menyesuaikan penyajian stroke secara dinamis, ambil alih OnDraw metode .

  2. Stroke: Terapkan kelas yang berasal dari Stroke. Kelas ini bertanggung jawab atas penyajian StylusPoint data statis setelah dikonversi menjadi Stroke objek. Ambil alih DrawCore metode untuk memastikan bahwa penyajian statis goresan konsisten dengan penyajian dinamis.

  3. InkCanvas: Terapkan kelas yang berasal dari InkCanvas. Tetapkan yang dikustomisasi DynamicRenderer ke DynamicRenderer properti . Ambil alih OnStrokeCollected metode dan tambahkan goresan kustom ke Strokes properti . Ini memastikan bahwa penampilan tinta konsisten.

Menerapkan Dynamic Renderer

DynamicRenderer Meskipun kelas adalah bagian standar dari WPF, untuk melakukan penyajian yang lebih khusus, Anda harus membuat perender dinamis yang disesuaikan yang berasal dari DynamicRenderer dan mengambil alih OnDraw metode .

Contoh berikut menunjukkan kustomisasi DynamicRenderer yang menggambar tinta dengan efek sikat gradien linier.

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

Menerapkan Stroke Kustom

Terapkan kelas yang berasal dari Stroke. Kelas ini bertanggung jawab untuk merender StylusPoint data setelah dikonversi menjadi Stroke objek. Ambil alih DrawCore kelas untuk melakukan gambar aktual.

Kelas Stroke Anda juga dapat menyimpan data kustom dengan menggunakan metode .AddPropertyData Data ini disimpan dengan data goresan saat dipertahankan.

Kelas juga Stroke dapat melakukan pengujian hit. Anda juga dapat menerapkan algoritma pengujian hit Anda sendiri dengan mengambil alih HitTest metode di kelas saat ini.

Kode C# berikut menunjukkan kelas kustom Stroke yang merender StylusPoint data sebagai goresan 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

Menerapkan InkCanvas Kustom

Cara term mudah untuk menggunakan kustomisasi DynamicRenderer dan stroke Anda adalah dengan mengimplementasikan kelas yang berasal dari InkCanvas dan menggunakan kelas-kelas ini. InkCanvas memiliki DynamicRenderer properti yang menentukan bagaimana goresan dirender ketika pengguna menggambarnya.

Untuk merender goresan kustom pada melakukan InkCanvas hal berikut:

Kode C# berikut menunjukkan kelas kustom InkCanvas yang menggunakan DynamicRenderer goresan kustom dan mengumpulkan goresan kustom.

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

Dapat InkCanvas memiliki lebih dari satu DynamicRenderer. Anda dapat menambahkan beberapa DynamicRenderer objek ke InkCanvas properti dengan menambahkannya ke StylusPlugIns properti .

Kesimpulan

Anda dapat menyesuaikan tampilan tinta dengan turunan kelas , , Strokedan InkCanvas Anda sendiriDynamicRenderer. Bersama-sama, kelas-kelas ini memastikan bahwa penampilan stroke konsisten ketika pengguna menarik stroke dan setelah dikumpulkan.

Baca juga