Практическое руководство. Поворот рукописного ввода
Пример
Следующий пример копирует рукописные данные из InkCanvas для Canvas , содержащий InkPresenter. Когда приложение копирует рукописные данные, он также сменяет рукописный ввод 90 градусов по часовой стрелке.
<Canvas>
<InkCanvas Name="inkCanvas1" Background="LightBlue"
Height="200" Width="200"
Canvas.Top="20" Canvas.Left="20" />
<Border Name="canvas1" Background="LightGreen"
Height="200" Width="200" ClipToBounds="True"
Canvas.Top="20" Canvas.Left="240" >
<InkPresenter Name="inkPresenter1"/>
</Border>
<Button Click="button_Click"
Canvas.Top="240" Canvas.Left="170">
Copy and Rotate Strokes
</Button>
</Canvas>
// Button.Click event handler that rotates the strokes
// and copies them to a Canvas.
private void button_Click(object sender, RoutedEventArgs e)
{
StrokeCollection copiedStrokes = inkCanvas1.Strokes.Clone();
Matrix rotatingMatrix = new Matrix();
double canvasLeft = Canvas.GetLeft(inkCanvas1);
double canvasTop = Canvas.GetTop(inkCanvas1);
Point rotatePoint = new Point(canvas1.Width / 2, canvas1.Height / 2);
rotatingMatrix.RotateAt(90, rotatePoint.X, rotatePoint.Y);
copiedStrokes.Transform(rotatingMatrix, false);
inkPresenter1.Strokes = copiedStrokes;
}
Пример
Следующий пример является пользовательским Adorner , поворачивающий штрихи на InkPresenter.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Ink;
public class RotatingStrokesAdorner : Adorner
{
// The Thumb to drag to rotate the strokes.
Thumb rotateHandle;
// The surrounding boarder.
Path outline;
VisualCollection visualChildren;
// The center of the strokes.
Point center;
double lastAngle;
RotateTransform rotation;
const int HANDLEMARGIN = 10;
// The bounds of the Strokes;
Rect strokeBounds = Rect.Empty;
public RotatingStrokesAdorner(UIElement adornedElement)
: base(adornedElement)
{
visualChildren = new VisualCollection(this);
rotateHandle = new Thumb();
rotateHandle.Cursor = Cursors.SizeNWSE;
rotateHandle.Width = 20;
rotateHandle.Height = 20;
rotateHandle.Background = Brushes.Blue;
rotateHandle.DragDelta += new DragDeltaEventHandler(rotateHandle_DragDelta);
rotateHandle.DragCompleted += new DragCompletedEventHandler(rotateHandle_DragCompleted);
outline = new Path();
outline.Stroke = Brushes.Blue;
outline.StrokeThickness = 1;
visualChildren.Add(outline);
visualChildren.Add(rotateHandle);
strokeBounds = AdornedStrokes.GetBounds();
}
/// <summary>
/// Draw the rotation handle and the outline of
/// the element.
/// </summary>
/// <param name="finalSize">The final area within the
/// parent that this element should use to arrange
/// itself and its children.</param>
/// <returns>The actual size used. </returns>
protected override Size ArrangeOverride(Size finalSize)
{
if (strokeBounds.IsEmpty)
{
return finalSize;
}
center = new Point(strokeBounds.X + strokeBounds.Width / 2,
strokeBounds.Y + strokeBounds.Height / 2);
// The rectangle that determines the position of the Thumb.
Rect handleRect = new Rect(strokeBounds.X,
strokeBounds.Y - (strokeBounds.Height / 2 +
HANDLEMARGIN),
strokeBounds.Width, strokeBounds.Height);
if (rotation != null)
{
handleRect.Transform(rotation.Value);
}
// Draws the thumb and the rectangle around the strokes.
rotateHandle.Arrange(handleRect);
outline.Data = new RectangleGeometry(strokeBounds);
outline.Arrange(new Rect(finalSize));
return finalSize;
}
/// <summary>
/// Rotates the rectangle representing the
/// strokes' bounds as the user drags the
/// Thumb.
/// </summary>
void rotateHandle_DragDelta(object sender, DragDeltaEventArgs e)
{
// Find the angle of which to rotate the shape. Use the right
// triangle that uses the center and the mouse's position
// as vertices for the hypotenuse.
Point pos = Mouse.GetPosition(this);
double deltaX = pos.X - center.X;
double deltaY = pos.Y - center.Y;
if (deltaY.Equals(0))
{
return;
}
double tan = deltaX / deltaY;
double angle = Math.Atan(tan);
// Convert to degrees.
angle = angle * 180 / Math.PI;
// If the mouse crosses the vertical center,
// find the complementary angle.
if (deltaY > 0)
{
angle = 180 - Math.Abs(angle);
}
// Rotate left if the mouse moves left and right
// if the mouse moves right.
if (deltaX < 0)
{
angle = -Math.Abs(angle);
}
else
{
angle = Math.Abs(angle);
}
if (Double.IsNaN(angle))
{
return;
}
// Apply the rotation to the strokes' outline.
rotation = new RotateTransform(angle, center.X, center.Y);
outline.RenderTransform = rotation;
}
/// <summary>
/// Rotates the strokes to the same angle as outline.
/// </summary>
void rotateHandle_DragCompleted(object sender,
DragCompletedEventArgs e)
{
if (rotation == null)
{
return;
}
// Rotate the strokes to match the new angle.
Matrix mat = new Matrix();
mat.RotateAt(rotation.Angle - lastAngle, center.X, center.Y);
AdornedStrokes.Transform(mat, true);
// Save the angle of the last rotation.
lastAngle = rotation.Angle;
// Redraw rotateHandle.
this.InvalidateArrange();
}
/// <summary>
/// Gets the strokes of the adorned element
/// (in this case, an InkPresenter).
/// </summary>
private StrokeCollection AdornedStrokes
{
get
{
return ((InkPresenter)AdornedElement).Strokes;
}
}
// Override the VisualChildrenCount and
// GetVisualChild properties to interface with
// the adorner's visual collection.
protected override int VisualChildrenCount
{
get { return visualChildren.Count; }
}
protected override Visual GetVisualChild(int index)
{
return visualChildren[index];
}
}
Ниже приведен пример XAML файл, который определяет InkPresenter и заполняет ее рукописного ввода. Window_Loaded
Обработчик событий добавляет пользовательский графический InkPresenter.
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Rotating Strokes Adorner" Height="500" Width="500"
Loaded="Window_Loaded"
>
<InkPresenter Name="inkPresenter1" >
<InkPresenter.Strokes>
ALMDAwRIEEU1BQE4GSAyCQD0/wIB6SI6RTMJAPifAgFaIDpFOAgA/gMAAACAfxEAAIA/
HwkRAAAAAAAA8D8KlwE1h/CPd4SB4NA4OicCjcGjcClcDj8Lh8DgUSkUmmU6nUmoUuk
0ukUCQKVyehz+rzuly+bzORx+BReRQ+RTaRCH8JyXhPbgcPicPh8Pg8Oh0qk1SoVGrV
Oo0mi0Xi8rm9Xr9Dqc/p87pc/k8XicHicOj1CoVKtVmv1GqUaiUHlYg8el4akXK7m7T
cSJgQgghEyym5zx6+PACk4dhPwg/fhCbxY8dp4p2tqnqxyvbPO85z1X1aswhvCd94Tq
55DRUGi4+Tk6OLn4KLkoOejo6ig5KTioOPCD9LlHmrzNxMRCCc3ec8+fe4AKQBmE/Cw
9+FkPNvlOdkrYsWa+acp3Z8erOIT8JaX4S6+FbFilbHNvvPXNJbFqluxghKc5DkwrVF
GEEIJ1w5eLKYAKShuF+Dnr4Oa8HVHXNPFFFFho8VFkqsMRYuuvJxiF+F9r4Xx8HFiqs
FNcirnweDw9+LvvvixdV0+GhONmlj3wjNOcSCEYTnfLy4oA
</InkPresenter.Strokes>
</InkPresenter>
</Window>
void Window_Loaded(object sender, RoutedEventArgs e)
{
// Add the rotating strokes adorner to the InkPresenter.
adornerLayer = AdornerLayer.GetAdornerLayer(inkPresenter1);
adorner = new RotatingStrokesAdorner(inkPresenter1);
adornerLayer.Add(adorner);
}