Пользовательская отрисовка рукописных данных
DrawingAttributes Свойство штриха позволяет задавать внешний вид штриха, включая его размер, цвет и форму, но могут возникнуть ситуации, которые вы хотите настроить внешний вид что DrawingAttributes разрешить. Может потребоваться настроить отображение рукописного фрагмента с эффектом аэрографа, масляной живописи и т. д. Windows Presentation Foundation (WPF) позволяет настроить отрисовку рукописных фрагментов путем реализации пользовательского DynamicRenderer и Stroke объекта.
В этом разделе содержатся следующие подразделы:
Архитектура
Отрисовка рукописных фрагментов происходит два раза: когда пользователь осуществляет рукописный ввод на поверхности рукописного ввода, а затем еще раз после добавления штриха в область с поддержкой рукописного ввода. DynamicRenderer Отрисовывает рукописные фрагменты при перемещении пера планшета по дигитайзеру, а Stroke отрисовывает сам себя после его добавления в элемент.
Предусмотрено три класса для реализации динамической отрисовки рукописных фрагментов.
DynamicRenderer: Реализация класса, унаследованного от класса DynamicRenderer. Этот класс является специализированным StylusPlugIn , отображающий штрих, так как он отрисовывается. DynamicRenderer Осуществляет отрисовку в отдельном потоке, поэтому поверхность рукописного ввода появляется для сбора рукописных фрагментов даже при блокировке потока пользовательского интерфейса приложения. Дополнительные сведения о потоковой модели см. в статье Потоковая модель рукописного ввода. Чтобы настроить динамическую отрисовку штриха, переопределите OnDraw метод.
Stroke: Реализация класса, унаследованного от класса Stroke. Этот класс отвечает за статическую отрисовку StylusPoint данные после преобразования в Stroke объекта. Переопределить DrawCore согласуется метод, чтобы гарантировать статической отрисовки штриха с динамической отрисовкой.
InkCanvas: Реализация класса, унаследованного от класса InkCanvas. Назначьте пользовательский DynamicRenderer для DynamicRenderer свойство. Переопределить OnStrokeCollected метод и добавьте пользовательский штрих в Strokes свойство. Это гарантирует согласованность внешнего вида рукописных фрагментов.
Реализация динамического отрисовщика
Несмотря на то что DynamicRenderer класс является стандартной частью WPF, для осуществления более специализированной отрисовки, необходимо создать настроенный динамический отрисовщик, производный от DynamicRenderer и переопределить OnDraw метод.
В следующем примере настраиваемый DynamicRenderer , который выполняет отрисовку рукописного ввода с эффектом кисти линейного градиента.
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using 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;
}
}
}
}
Реализация пользовательских штрихов
Реализация класса, унаследованного от класса Stroke. Этот класс отвечает за отрисовку StylusPoint данные после преобразования в Stroke объекта. Переопределить DrawCore класс для фактического рисования.
Класс Stroke также может хранить пользовательские данные с помощью AddPropertyData метод. Эти данные хранятся с данными штриха при сохранении.
Stroke Класс также может выполнять проверку нажатия. Вы также можете реализовать собственный алгоритм проверки совпадений путем переопределения HitTest метода в текущем классе.
Следующие C# код демонстрирует пользовательский Stroke класс, который выполняет визуализацию StylusPoint данные в виде трехмерного штриха.
using System;
using System.Windows.Media;
using System.Windows;
using System.Windows.Input.StylusPlugIns;
using System.Windows.Input;
using 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;
}
}
}
}
Реализация пользовательского объекта InkCanvas
Самый простой способ применения пользовательского DynamicRenderer и штриха является реализация класса, производного от InkCanvas и использует эти классы. InkCanvas Имеет DynamicRenderer свойство, которое указывает, каким образом отображается штрих, когда пользователь рисует его.
Для отображения пользовательских штрихов на InkCanvas выполните следующие действия:
Создайте класс, производный от InkCanvas.
Назначьте пользовательский DynamicRenderer для InkCanvas.DynamicRenderer свойство.
Переопределите метод OnStrokeCollected . В этом методе удалите исходный штрих, который был добавлен в InkCanvas. Затем создайте пользовательский штрих, добавьте ее в Strokes и вызовите базовый класс с новым InkCanvasStrokeCollectedEventArgs , содержащим пользовательский штрих.
Следующие C# код демонстрирует пользовательский InkCanvas класс, который использует настраиваемый DynamicRenderer и сбор пользовательских штрихов.
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);
}
}
InkCanvas Может иметь несколько DynamicRenderer. Можно добавить несколько DynamicRenderer объектов InkCanvas , добавив их в StylusPlugIns свойство.
Заключение
Можно настроить отображение рукописного фрагмента путем наследования своих собственных DynamicRenderer, Stroke, и InkCanvas классы. Вместе эти классы гарантируют согласованность внешнего вида штриха в момент, когда пользователь рисует штрих, и после его сбора.