Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
DrawingAttributes Właściwość pociągnięcia umożliwia określenie wyglądu pociągnięcia, takiego jak jego rozmiar, kolor i kształt, ale może istnieć czas, w którym chcesz dostosować wygląd poza tym, co DrawingAttributes pozwala. Możesz dostosować wygląd atramentu, renderując w wyglądzie pędzla powietrza, farby olejnej i wielu innych efektów. Program Windows Presentation Foundation (WPF) umożliwia niestandardowe renderowanie pisma odręcznego przez zaimplementowanie niestandardowego DynamicRenderer obiektu i Stroke .
Ten temat zawiera następujące podsekcje:
Architektura
Renderowanie rysowania atramentem odbywa się dwa razy; gdy użytkownik zapisuje atrament na powierzchni atramentowej i ponownie po dodaniu pociągnięcia do powierzchni obsługującej atrament. Funkcja DynamicRenderer renderuje atrament, gdy użytkownik przenosi pióro tabletu na digitizer, a Stroke sam renderuje się po dodaniu go do elementu.
Istnieją trzy klasy do wdrożenia podczas dynamicznego renderowania atramentu.
DynamicRenderer: zaimplementuj klasę pochodzącą z klasy DynamicRenderer. Ta klasa jest wyspecjalizowana StylusPlugIn , która renderuje pociągnięcie podczas rysowania. Wykonuje DynamicRenderer renderowanie w osobnym wątku, więc powierzchnia tuszu wydaje się zbierać tusz nawet wtedy, gdy wątek interfejsu użytkownika aplikacji jest zablokowany. Aby uzyskać więcej informacji na temat modelu wątkowania, zobacz Model wątkowania atramentu. Aby dostosować dynamiczne rysowanie kreski, zastąp metodę OnDraw.
Stroke: zaimplementuj klasę, która dziedziczy po Stroke. Ta klasa jest odpowiedzialna za statyczne renderowanie StylusPoint danych po jego przekonwertowaniu na Stroke obiekt. Zastąpij metodę DrawCore , aby upewnić się, że renderowanie statyczne pociągnięcia jest spójne z renderowaniem dynamicznym.
InkCanvas: Zaimplementuj klasę pochodzącą z klasy InkCanvas. Przypisz właściwość dostosowaną DynamicRendererDynamicRenderer do właściwości . Zastąp metodę OnStrokeCollected i dodaj niestandardowy obrys do właściwości Strokes. Dzięki temu wygląd atramentu jest jednolity.
Implementowanie dynamicznego modułu renderowania
Mimo że klasa DynamicRenderer jest standardową częścią WPF, aby wykonać bardziej wyspecjalizowane renderowanie, należy utworzyć dostosowany dynamiczny renderer, który pochodzi z DynamicRenderer, i zastąpić metodę OnDraw.
W poniższym przykładzie pokazano dostosowany DynamicRenderer atrament, który rysuje atrament z efektem pędzla gradientowego liniowego.
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
Implementowanie niestandardowych obramowań
Zaimplementuj klasę pochodzącą z klasy Stroke. Ta klasa jest odpowiedzialna za renderowanie StylusPoint danych po przekonwertowaniu ich na Stroke obiekt. Zastąp klasę DrawCore, aby wykonać rzeczywiste rysowanie.
Klasa Stroke może również przechowywać dane niestandardowe przy użyciu metody AddPropertyData. Te dane są przechowywane wraz z danymi pociągnięcia po utrwaleniu.
Klasa Stroke może również przeprowadzać testowanie trafień. Możesz również zaimplementować własny algorytm testowania trafień, przeciążając metodę HitTest w bieżącej klasie.
Poniższy kod w języku C# przedstawia klasę niestandardową Stroke , która renderuje StylusPoint dane jako pociągnięcie 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
Implementowanie niestandardowego modułu InkCanvas
Najprostszym sposobem użycia dostosowanego DynamicRenderer i pociągnięcia jest zaimplementowanie klasy, która pochodzi z InkCanvas i używa tych klas. InkCanvas ma właściwość DynamicRenderer, która określa sposób renderowania pociągnięcia podczas rysowania go przez użytkownika.
Aby zastosować niestandardowe renderowanie pociągnięć na InkCanvas, wykonaj następujące czynności:
Utwórz klasę, która pochodzi z klasy InkCanvas.
Przypisz swoje dostosowane DynamicRenderer do właściwości InkCanvas.DynamicRenderer.
Zastąp metodę OnStrokeCollected. W tej metodzie usuń oryginalny obrys, który został dodany do InkCanvas. Następnie utwórz niestandardowe pociągnięcia, dodaj je do właściwości Strokes, a następnie wywołaj klasę bazową, przekazując nowy element InkCanvasStrokeCollectedEventArgs, zawierający niestandardowe pociągnięcie.
Poniższy kod w języku C# demonstruje niestandardową klasę InkCanvas, która używa dostosowanego DynamicRenderer i zbiera niestandardowe linie.
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);
}
}
Obiekt InkCanvas może mieć więcej niż jeden DynamicRenderer element. Można dodać wiele obiektów DynamicRenderer do InkCanvas, dodając je do właściwości StylusPlugIns.
Podsumowanie
Można dostosować wygląd atramentu, tworząc własne klasy DynamicRenderer, Stroke, i InkCanvas. Razem te klasy zapewniają, że wygląd pociągnięcia jest spójny, gdy użytkownik rysuje pociągnięcie i po jego ukończeniu.
Zobacz także
.NET Desktop feedback