重新想象 Windows 8 Store Apps (51) - 输入: 涂鸦板
作者:webabcd
介绍
重新想象 Windows 8 Store Apps 之 涂鸦板
- 通过 Pointer 相关事件实现一个具有基本功能的涂鸦板
- 通过 InkManager 实现一个功能完善的涂鸦板
示例
1、演示如何通过 Pointer 相关事件实现一个只有基本功能的涂鸦板
Input/Ink/Simple.xaml
<Page
x:Class="XamlDemo.Input.Ink.Simple"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Input.Ink"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <Button Name="btnClear" Content="清除" Click="btnClear_Click_1" /> <Canvas Name="canvas" Background="Blue" Width="800" Height="480" HorizontalAlignment="Left" Margin="0 10 0 0" /> </StackPanel>
</Grid>
</Page>
Input/Ink/Simple.xaml.cs
/*
* 通过 Pointer 相关事件实现一个只有基本功能的涂鸦板
*/ using System;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes; namespace XamlDemo.Input.Ink
{
public sealed partial class Simple : Page
{
// 用于保存触摸点(PointerId - Point)
private Dictionary<uint, Point?> _dicPoint; public Simple()
{
this.InitializeComponent(); canvas.PointerPressed += canvas_PointerPressed;
canvas.PointerMoved += canvas_PointerMoved;
canvas.PointerReleased += canvas_PointerReleased;
canvas.PointerExited += canvas_PointerExited; _dicPoint = new Dictionary<uint, Point?>();
} void canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// 指针按下后,保存此触摸点
PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
_dicPoint[pointerPoint.PointerId] = pointerPoint.Position;
} void canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
{
PointerPoint pointerPoint = e.GetCurrentPoint(canvas); if (_dicPoint.ContainsKey(pointerPoint.PointerId) && _dicPoint[pointerPoint.PointerId].HasValue)
{
Point currentPoint = pointerPoint.Position;
Point previousPoint = _dicPoint[pointerPoint.PointerId].Value; // 如果指针移动过程中,两个点间的距离超过 4 则在两点间绘制一条直线,以完成涂鸦
if (ComputeDistance(currentPoint, previousPoint) > )
{
Line line = new Line()
{
X1 = previousPoint.X,
Y1 = previousPoint.Y,
X2 = currentPoint.X,
Y2 = currentPoint.Y,
StrokeThickness = ,
Stroke = new SolidColorBrush(Colors.Orange),
StrokeEndLineCap = PenLineCap.Round
}; _dicPoint[pointerPoint.PointerId] = currentPoint;
canvas.Children.Add(line);
}
}
} void canvas_PointerReleased(object sender, PointerRoutedEventArgs e)
{
// 指针释放后,从字典中删除此 PointerId 的数据
PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
if (_dicPoint.ContainsKey(pointerPoint.PointerId))
_dicPoint.Remove(pointerPoint.PointerId);
} void canvas_PointerExited(object sender, PointerRoutedEventArgs e)
{
// 指针离开相当于指针释放
canvas_PointerReleased(sender, e);
} // 清除涂鸦
private void btnClear_Click_1(object sender, RoutedEventArgs e)
{
canvas.Children.Clear();
_dicPoint.Clear();
} // 计算两个点(Point)之间的距离
private double ComputeDistance(Point point1, Point point2)
{
return Math.Sqrt(Math.Pow(point1.X - point2.X, ) + Math.Pow(point1.Y - point2.Y, ));
}
}
}
2、演示如何通过 InkManager 实现一个功能完善的涂鸦板
Input/Ink/InkRenderer.cs
/*
* 开发一个 InkRenderer 类,用于呈现 InkManager 中的内容
*
* 注:InkManager 用于 ink 的管理,但并不负责呈现
*
*
* InkStroke - ink 画笔
* DrawingAttributes - 画笔的相关属性,一个 InkDrawingAttributes 类型的对象
* Color - 颜色
* FitToCurve - 使用贝塞尔曲线则为 true,使用直线则为 false,默认值为 true
* PenTip - 笔尖的形状(Circle, Rectangle)
* Size - 笔尖的尺寸
* IgnorePressure - 是否忽略笔尖在触摸屏上的压力
* BoundingRect - ink 画笔的边界框
* Recognized - 该画笔是否已被文字识别
* Selected - 该画笔是否被选中
* Clone() - 克隆这个画笔,并返回克隆后的新的 InkStroke 对象
* GetRenderingSegments() - 返回 ink 的线段集合,即 InkStrokeRenderingSegment 集合
*
* InkStrokeRenderingSegment - ink 的线段
* BezierControlPoint1 - 贝塞尔曲线的第一个控制点的位置
* BezierControlPoint2 - 贝塞尔曲线的第二个控制点的位置
* Position - 贝塞尔曲线的终点的位置
*/ using System.Collections.Generic;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes; namespace XamlDemo.Input.Ink
{
public class InkRenderer
{
/// <summary>
/// 呈现 ink 的容器
/// </summary>
private readonly Panel _container = null; /// <summary>
/// ink 的实时路径(PointerId - Path)
/// </summary>
private readonly Dictionary<uint, Path> _dicLivePath = null;
/// <summary>
/// ink 的实时路径中所包含的 PolyLineSegment(PointerId - PolyLineSegment)
/// </summary>
private readonly Dictionary<uint, PolyLineSegment> _dicLivePolyLine = null; /// <summary>
/// InkStroke 所对应三次贝塞尔曲线,用于保存全部涂鸦曲线(包括未被选中的和被选中的)
/// </summary>
private readonly Dictionary<InkStroke, Path> _dicInkPath = null;
/// <summary>
/// InkStroke 所对应三次贝塞尔曲线,用于保存被选中的涂鸦曲线
/// </summary>
private readonly Dictionary<InkStroke, Path> _dicSelectionPath = null; /// <summary>
/// 构造函数
/// </summary>
/// <param name="panel">用于呈现 ink 的容器</param>
public InkRenderer(Panel panel)
{
_container = panel; _dicLivePath = new Dictionary<uint, Path>();
_dicLivePolyLine = new Dictionary<uint, PolyLineSegment>(); _dicInkPath = new Dictionary<InkStroke, Path>();
_dicSelectionPath = new Dictionary<InkStroke, Path>();
} /// <summary>
/// 开始实时绘制 ink
/// </summary>
/// <param name="pointerPoint">当前的触摸点</param>
/// <param name="inkDrawingAttributes">ink 的 InkDrawingAttributes 数据</param>
public void EnterLiveRendering(PointerPoint pointerPoint, InkDrawingAttributes inkDrawingAttributes)
{
uint pointerId = pointerPoint.PointerId; var polyLine = new PolyLineSegment();
polyLine.Points.Add(pointerPoint.Position);
var figure = new PathFigure();
figure.StartPoint = pointerPoint.Position;
figure.Segments.Add(polyLine);
var geometry = new PathGeometry();
geometry.Figures.Add(figure);
var path = new Path();
path.Data = geometry; path.Stroke = new SolidColorBrush(inkDrawingAttributes.Color);
path.StrokeThickness = inkDrawingAttributes.Size.Width;
path.StrokeLineJoin = PenLineJoin.Round;
path.StrokeStartLineCap = PenLineCap.Round; _dicLivePolyLine.Add(pointerId, polyLine);
_dicLivePath.Add(pointerId, path); _container.Children.Add(path);
} /// <summary>
/// 更新 ink 的实时绘制
/// </summary>
/// <param name="pointerPoint"></param>
public void UpdateLiveRender(PointerPoint pointerPoint)
{
uint pointerId = pointerPoint.PointerId; _dicLivePolyLine[pointerId].Points.Add(pointerPoint.Position);
} /// <summary>
/// 停止此次 ink 的实时绘制
/// </summary>
/// <param name="pointerPoint">涂鸦的停止点</param>
public void ExitLiveRendering(PointerPoint pointerPoint)
{
uint pointerId = pointerPoint.PointerId; _container.Children.Remove(_dicLivePath[pointerId]); _dicLivePolyLine.Remove(pointerId);
_dicLivePath.Remove(pointerId);
} /// <summary>
/// 将 InkStroke 绘制成一条三次贝塞尔曲线
/// </summary>
/// <param name="inkStroke">InkStroke 对象</param>
public void UpdateInkRender(InkStroke inkStroke)
{
Path bezierPath = InkStroke2BezierPath(inkStroke);
_dicInkPath.Add(inkStroke, bezierPath);
_container.Children.Add(bezierPath);
} /// <summary>
/// 将每一个 InkStroke 都绘制成一条三次贝塞尔曲线
/// </summary>
/// <param name="inkStrokes">InkStroke 集合</param>
public void UpdateInkRender(IEnumerable<InkStroke> inkStrokes)
{
foreach (InkStroke inkStroke in inkStrokes)
{
UpdateInkRender(inkStroke);
}
} /// <summary>
/// 将被选中的 InkStroke 以被选中的样式绘制出来
/// </summary>
public void UpdateSelectionRender()
{
foreach (var inkPath in _dicInkPath)
{
Path selectionPath = null;
bool selectionPathExists = _dicSelectionPath.TryGetValue(inkPath.Key, out selectionPath); // 如果 InkStroke 是被选中的状态,但是并没有呈现出选中状态,则呈现这个选中状态
if (inkPath.Key.Selected && !selectionPathExists)
{
inkPath.Value.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width + ; selectionPath = InkStroke2BezierPath(inkPath.Key);
selectionPath.Stroke = new SolidColorBrush(Colors.White);
selectionPath.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width;
_dicSelectionPath.Add(inkPath.Key, selectionPath); _container.Children.Add(selectionPath);
}
// 如果 InkStroke 是未被选中的状态,但是却呈现出选中状态,则去掉这个选中状态的呈现
else if (selectionPathExists)
{
inkPath.Value.StrokeThickness = inkPath.Key.DrawingAttributes.Size.Width;
_dicSelectionPath.Remove(inkPath.Key);
_container.Children.Remove(selectionPath);
}
}
} /// <summary>
/// 清除全部呈现
/// </summary>
public void Clear()
{
foreach (var path in _dicInkPath.Values)
{
_container.Children.Remove(path);
}
foreach (var path in _dicSelectionPath.Values)
{
_container.Children.Remove(path);
}
foreach (var path in _dicLivePath.Values)
{
_container.Children.Remove(path);
} _dicInkPath.Clear();
_dicSelectionPath.Clear();
_dicLivePath.Clear();
_dicLivePolyLine.Clear();
} /// <summary>
/// 如果 InkStroke 是一个贝塞尔曲线画笔,则可将其转换成 Path(一条贝塞尔曲线)
/// </summary>
/// <param name="inkStroke">InkStroke 对象</param>
/// <returns>转换后的 Path 对象</returns>
public static Path InkStroke2BezierPath(InkStroke inkStroke)
{
var figure = new PathFigure();
var segments = inkStroke.GetRenderingSegments().GetEnumerator();
segments.MoveNext(); figure.StartPoint = segments.Current.Position; while (segments.MoveNext())
{
var bs = new BezierSegment();
bs.Point1 = segments.Current.BezierControlPoint1;
bs.Point2 = segments.Current.BezierControlPoint2;
bs.Point3 = segments.Current.Position;
figure.Segments.Add(bs);
} var geometry = new PathGeometry();
geometry.Figures.Add(figure);
var path = new Path();
path.Data = geometry; path.Stroke = new SolidColorBrush(inkStroke.DrawingAttributes.Color);
path.StrokeThickness = inkStroke.DrawingAttributes.Size.Width;
path.StrokeLineJoin = PenLineJoin.Round;
path.StrokeStartLineCap = PenLineCap.Round; return path;
}
}
}
Input/Ink/Demo.xaml
<Page
x:Class="XamlDemo.Input.Ink.Demo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:XamlDemo.Input.Ink"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"> <Grid Background="Transparent">
<StackPanel Margin="120 0 0 0"> <TextBlock Name="lblMsg" FontSize="14.667" /> <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<RadioButton Name="radInk" GroupName="mode" Content="涂鸦模式" Checked="radInk_Checked_1" IsChecked="True" />
<RadioButton Name="radSelect" GroupName="mode" Content="选择模式" Checked="radSelect_Checked_1" Margin="10 0 0 0" />
<RadioButton Name="radErase" GroupName="mode" Content="删除模式" Checked="radErase_Checked_1" Margin="10 0 0 0" />
</StackPanel> <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<Button Name="btnClearAll" Content="清除全部内容" Click="btnClearAll_Click_1" />
<Button Name="btnClearSelectedInk" Content="清除被选中的内容" Click="btnClearSelectedInk_Click_1" Margin="10 0 0 0" />
<Button Name="btnClearSelectedState" Content="清除选中状态" Click="btnClearSelectedState_Click_1" Margin="10 0 0 0" />
<Button Name="btnMoveSelectedInk" Content="移动被选中的内容" Click="btnMoveSelectedInk_Click_1" Margin="10 0 0 0" />
</StackPanel> <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<Button Name="btnCut" Content="剪切" Click="btnCut_Click_1" />
<Button Name="btnCopy" Content="复制" Click="btnCopy_Click_1" Margin="10 0 0 0" />
<Button Name="btnPaste" Content="粘贴" Click="btnPaste_Click_1" Margin="10 0 0 0" />
</StackPanel> <StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<Button Name="btnSave" Content="保存到文件" Click="btnSave_Click_1" />
<Button Name="btnLoad" Content="从文件加载" Click="btnLoad_Click_1" Margin="10 0 0 0" />
<Button Name="btnRecognize" Content="文字识别" Click="btnRecognize_Click_1" Margin="10 0 0 0" />
</StackPanel> <Canvas x:Name="canvas" Background="Blue" Width="800" Height="360" Margin="0 10 0 0" HorizontalAlignment="Left"
PointerPressed="canvas_PointerPressed_1"
PointerMoved="canvas_PointerMoved_1"
PointerReleased="canvas_PointerReleased_1" /> </StackPanel>
</Grid>
</Page>
Input/Ink/Demo.xaml.cs
/*
* 通过 InkManager 实现一个功能完善的涂鸦板
*
* 注:InkManager 用于 ink 的管理,但并不负责呈现,需要自己开发呈现 ink 的类,请参见 InkRenderer.cs
*
*
* InkManager - ink 的管理类
* 包括 ink 的输入模式,复制/粘贴,移动,保存到文件,从文件加载,文字识别等功能
* 详细说明请参见本 Demo 中的相关代码的注释
*
* InkStroke - ink 画笔
* DrawingAttributes - 画笔的相关属性,一个 InkDrawingAttributes 类型的对象
* Color - 颜色
* FitToCurve - 使用贝塞尔曲线则为 true,使用直线则为 false,默认值为 true
* PenTip - 笔尖的形状(Circle, Rectangle)
* Size - 笔尖的尺寸
* IgnorePressure - 是否忽略笔尖在触摸屏上的压力
* BoundingRect - ink 画笔的边界框
* Recognized - 该画笔是否已被文字识别
* Selected - 该画笔是否被选中
* Clone() - 克隆这个画笔,并返回克隆后的新的 InkStroke 对象
* GetRenderingSegments() - 返回 ink 的线段集合,即 InkStrokeRenderingSegment 集合
*
* InkStrokeRenderingSegment - ink 的线段
* BezierControlPoint1 - 贝塞尔曲线的第一个控制点的位置
* BezierControlPoint2 - 贝塞尔曲线的第二个控制点的位置
* Position - 贝塞尔曲线的终点的位置
*/ using System;
using System.Linq;
using System.Collections.Generic;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using XamlDemo.Common; namespace XamlDemo.Input.Ink
{
public sealed partial class Demo : Page
{
// 自己开发的用于呈现 ink 的类
private InkRenderer _renderer = null; private InkManager _inkManager = null;
private InkDrawingAttributes _inkDrawingAttributes = null; // 涂鸦 ink 的样式
private InkDrawingAttributes _inkDrawingAttributesForSelect = null; // 选择模式时,用于呈现用户的选择路径的 ink 的样式 private int _pointerId = -; // 当前指针的 pointerId public Demo()
{
this.InitializeComponent(); _inkDrawingAttributes = new InkDrawingAttributes();
_inkDrawingAttributes.Color = Colors.Orange;
_inkDrawingAttributes.Size = new Size(, );
_inkDrawingAttributes.IgnorePressure = true;
_inkDrawingAttributes.FitToCurve = true; _inkDrawingAttributesForSelect = new InkDrawingAttributes();
_inkDrawingAttributesForSelect.Color = Colors.White;
_inkDrawingAttributesForSelect.Size = new Size(, );
_inkDrawingAttributesForSelect.PenTip = PenTipShape.Circle; _inkManager = new InkManager();
// InkManager 一共有三种模式:Inking - 涂鸦;Erasing - 擦除;Selecting - 选择
_inkManager.Mode = InkManipulationMode.Inking;
// 设置 InkManager 的默认的画笔属性
_inkManager.SetDefaultDrawingAttributes(_inkDrawingAttributes);
// 获取 InkManager 所支持的文字识别的种类
var inkRecognizers = _inkManager.GetRecognizers();
var inkRecognizer = inkRecognizers.SingleOrDefault(p => p.Name.Equals("Microsoft 中文(简体)手写识别器"));
if (inkRecognizer != null)
{
// 设置 InkManager 的默认的文字识别器为“Microsoft 中文(简体)手写识别器”
_inkManager.SetDefaultRecognizer(inkRecognizer);
} _renderer = new InkRenderer(canvas);
} private void canvas_PointerPressed_1(object sender, PointerRoutedEventArgs e)
{
PointerPoint pointerPoint = e.GetCurrentPoint(canvas);
_pointerId = (int)pointerPoint.PointerId; switch (_inkManager.Mode)
{
case InkManipulationMode.Erasing: // 擦除模式
break;
case InkManipulationMode.Inking: // 涂鸦模式
_renderer.EnterLiveRendering(pointerPoint, _inkDrawingAttributes);
break;
case InkManipulationMode.Selecting: // 选择模式
_renderer.EnterLiveRendering(pointerPoint, _inkDrawingAttributesForSelect);
break;
default:
break;
} // 通知 InkManager 指针已按下
_inkManager.ProcessPointerDown(pointerPoint);
} private void canvas_PointerMoved_1(object sender, PointerRoutedEventArgs e)
{
PointerPoint pointerPoint = e.GetCurrentPoint(canvas); if (_pointerId == (int)pointerPoint.PointerId)
{
switch (_inkManager.Mode)
{
case InkManipulationMode.Erasing:
// 通知 InkManager 指针移动中,然后会返回一个 Rect 对象,其代表被 Erasing 的矩形范围
var erasingRect = (Rect)_inkManager.ProcessPointerUpdate(e.GetCurrentPoint(canvas));
if (erasingRect.Height != && erasingRect.Width != )
{
_renderer.Clear();
// 通过 InkManager.GetStrokes() 获取 InkManager 包含的全部 InkStroke 对象集合
_renderer.UpdateInkRender(_inkManager.GetStrokes());
}
break;
case InkManipulationMode.Inking:
case InkManipulationMode.Selecting:
if (_inkManager.Mode == InkManipulationMode.Inking || _inkManager.Mode == InkManipulationMode.Selecting)
{
var intermediatePoints = e.GetIntermediatePoints(canvas);
for (int i = intermediatePoints.Count - ; i >= ; i--)
{
// 通知 InkManager 指针移动中
_inkManager.ProcessPointerUpdate(intermediatePoints[i]);
} _renderer.UpdateLiveRender(pointerPoint);
}
break;
default:
break;
}
}
} private void canvas_PointerReleased_1(object sender, PointerRoutedEventArgs e)
{
PointerPoint pointerPoint = e.GetCurrentPoint(canvas); if (_pointerId == (int)pointerPoint.PointerId)
{
_pointerId = -; // 通知 InkManager 指针释放了,返回值:当 Inking 或 Selecting 时返回值为用户此次操作的矩形范围;当 Erasing 时返回值为 0,0,0,0
var rect = _inkManager.ProcessPointerUp(pointerPoint);
// var inkManagerRect = _inkManager.BoundingRect; // InkManager 所管理 InkStroke 集合的矩形范围(矩形边框) switch (_inkManager.Mode)
{
case InkManipulationMode.Inking:
_renderer.ExitLiveRendering(pointerPoint);
_renderer.UpdateInkRender(_inkManager.GetStrokes()[_inkManager.GetStrokes().Count - ]);
break;
case InkManipulationMode.Selecting:
_renderer.ExitLiveRendering(pointerPoint);
_renderer.UpdateSelectionRender();
break;
default:
break;
}
}
} private async void btnSave_Click_1(object sender, RoutedEventArgs e)
{
if (_inkManager.GetStrokes().Count > )
{
if (Helper.EnsureUnsnapped())
{
var savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("GIF", new List<string> { ".gif" }); StorageFile file = await savePicker.PickSaveFileAsync();
if (null != file)
{
using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
// 将 InkManager 中的 InkStroke 对象集合保存为文件
await _inkManager.SaveAsync(stream);
}
}
}
}
} private async void btnLoad_Click_1(object sender, RoutedEventArgs e)
{
if (Helper.EnsureUnsnapped())
{
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".gif");
StorageFile file = await openPicker.PickSingleFileAsync();
if (null != file)
{
using (var stream = await file.OpenSequentialReadAsync())
{
// 加载一个文件,从中获取 InkStroke 对象集合,并将其交由 InkManager 管理
await _inkManager.LoadAsync(stream);
} _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
}
}
} private void radInk_Checked_1(object sender, RoutedEventArgs e)
{
if (_inkManager != null)
_inkManager.Mode = InkManipulationMode.Inking; // 涂鸦模式
} private void radSelect_Checked_1(object sender, RoutedEventArgs e)
{
if (_inkManager != null)
_inkManager.Mode = InkManipulationMode.Selecting; // 选择模式
} private void radErase_Checked_1(object sender, RoutedEventArgs e)
{
if (_inkManager != null)
_inkManager.Mode = InkManipulationMode.Erasing; // 擦除模式
} private void btnCut_Click_1(object sender, RoutedEventArgs e)
{
// 将 InkManager 中的被选中的 InkStroke 对象集合复制到剪切板
_inkManager.CopySelectedToClipboard();
// 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
_inkManager.DeleteSelected(); _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
} private void btnCopy_Click_1(object sender, RoutedEventArgs e)
{
// 将 InkManager 中的被选中的 InkStroke 对象集合复制到剪切板
_inkManager.CopySelectedToClipboard();
} private void btnPaste_Click_1(object sender, RoutedEventArgs e)
{
// 剪切板中的数据是否是 InkStroke 对象集合
if (_inkManager.CanPasteFromClipboard())
{
// 将剪切板中的 InkStroke 对象集合粘贴到指定位置,并将此 InkStroke 对象集合交由 InkManager 管理
_inkManager.PasteFromClipboard(new Point(, )); _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
_renderer.UpdateSelectionRender();
}
} private void btnClearAll_Click_1(object sender, RoutedEventArgs e)
{
// 通过 InkManager.GetStrokes() 获取 InkManager 包含的全部 InkStroke 对象集合
foreach (var inkStroke in _inkManager.GetStrokes())
{
// InkStroke 是否被选中
inkStroke.Selected = true;
}
// 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
_inkManager.DeleteSelected(); _renderer.Clear();
} private void btnClearSelectedInk_Click_1(object sender, RoutedEventArgs e)
{
// 将 InkManager 中的被选中的 InkStroke 对象集合删除掉
_inkManager.DeleteSelected(); _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
} private void btnClearSelectedState_Click_1(object sender, RoutedEventArgs e)
{
foreach (var inkStroke in _inkManager.GetStrokes())
{
// InkStroke 是否被选中
inkStroke.Selected = false;
} _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
} private void btnMoveSelectedInk_Click_1(object sender, RoutedEventArgs e)
{
// 将 InkManager 中的被选中的 InkStroke 对象集合移动指定的距离(本例为向下移动 5 个像素,向右移动 50 个像素)
_inkManager.MoveSelected(new Point(, )); _renderer.Clear();
_renderer.UpdateInkRender(_inkManager.GetStrokes());
_renderer.UpdateSelectionRender();
} private async void btnRecognize_Click_1(object sender, RoutedEventArgs e)
{
// 对 InkManager 中的内容做文字识别
// InkRecognitionTarget.All - 识别全部;
// InkRecognitionTarget.Selected - 识别选中的 InkStroke 集合;
// InkRecognitionTarget.Recent - 识别最近的 InkStroke
var recognitionResults = await _inkManager.RecognizeAsync(InkRecognitionTarget.All);
// 将文字识别的结果更新到 InkManager
_inkManager.UpdateRecognitionResults(recognitionResults);
// _inkManager.GetRecognitionResults(); 获取 InkManager 中的文字识别的结果 string result = "文字识别的结果:";
foreach (InkRecognitionResult recognitionResult in recognitionResults)
{
// 获取此文字识别的所有可能的结果集合,集合的第一条数据为最匹配的结果
result += " " + recognitionResult.GetTextCandidates()[];
} lblMsg.Text = result;
}
}
}
OK
[源码下载]
重新想象 Windows 8 Store Apps (51) - 输入: 涂鸦板的更多相关文章
- 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop
[源码下载] 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop 作者:weba ...
- 重新想象 Windows 8 Store Apps (50) - 输入: 边缘手势, 手势操作, 手势识别
[源码下载] 重新想象 Windows 8 Store Apps (50) - 输入: 边缘手势, 手势操作, 手势识别 作者:webabcd 介绍重新想象 Windows 8 Store Apps ...
- 重新想象 Windows 8 Store Apps 系列文章索引
[源码下载][重新想象 Windows 8.1 Store Apps 系列文章] 重新想象 Windows 8 Store Apps 系列文章索引 作者:webabcd 1.重新想象 Windows ...
- 重新想象 Windows 8 Store Apps (38) - 契约: Search Contract
[源码下载] 重新想象 Windows 8 Store Apps (38) - 契约: Search Contract 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 ...
- 重新想象 Windows 8 Store Apps (39) - 契约: Share Contract
[源码下载] 重新想象 Windows 8 Store Apps (39) - 契约: Share Contract 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 ...
- 重新想象 Windows 8 Store Apps (56) - 系统 UI: Scale, Snap, Orientation, High Contrast 等
[源码下载] 重新想象 Windows 8 Store Apps (56) - 系统 UI: Scale, Snap, Orientation, High Contrast 等 作者:webabcd ...
- 重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的生命周期和程序的生命周期
[源码下载] 重新想象 Windows 8 Store Apps (70) - 其它: 文件压缩和解压缩, 与 Windows 商店相关的操作, app 与 web, 几个 Core 的应用, 页面的 ...
- 重新想象 Windows 8 Store Apps (71) - 其它: C# 调用 C++
[源码下载] 重新想象 Windows 8 Store Apps (71) - 其它: C# 调用 C++ 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 其它 C# ...
- 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试
原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...
随机推荐
- 首次构建android studio gradle 下载缓慢的问题
1.先使用其他工具下载gradle, https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 2.然后放在C:\Users\A ...
- Mac OS X下Sublime Text (V2.0.1)破解
转自:http://blog.sina.com.cn/s/blog_559d66460101cab0.html 1. 在http://www.sublimetext.com/上根据操作系统选择对应版本 ...
- React Native 重新建项目遇到的一些问题
1.基本上一句话,就是本地的node太旧了,跟不上React_Native的节奏,所以需要更新node,但是单纯的更新node丫丫竟然不让我跟,因为是用Homebrew来管理的,所以先update了下 ...
- 头文件 string.h cstring string 区别
1.#include <cstring> //不可以定义string s:可以用到strcpy等函数using namespace std; #include <stri ...
- 如何使用新浪微博账户进行应用登录验证(基于Windows Azure Mobile Service 集成登录验证)
使用三方账号登录应用应该对大家来说已经不是什么新鲜事儿了,但是今天为什么还要在这里跟大家聊这个话题呢,原因很简单 Windows Azure Mobiles Service Authenticatio ...
- 解析表达式到lucene.net的Query
查询的时候有自己的查询格式,为了统一并且方便的搜索lucene.net 于是就写了个解析格式,大体上覆盖了几乎所有的lucene.net的query了.当然少了公共扩展库里包含的regexQuery, ...
- 二叉树系列 - 二叉搜索树 - 线性时间内把有序链表转化为BST
引言 本文来自于Google的一道题目: how to merge two binary search tree into balanced binary search tree. how to me ...
- php 将一个二维数组转换成有父子关系的数组
<?php /** * Tree 树型类(无限分类) * * @author Kvoid * @copyright http://kvoid.com * @version 1.0 * @acce ...
- ios auto layout demystified (二)
Constraints Constraint Types Layout constraints (NSLayoutConstraint class, public)—这些规则指定了view的几何学.他 ...
- MyBatis自定义数据映射TypeHandler
从网上看到的帖子,感觉内容非常好,拷过来的(不愿意转载,不然被作者删除了,这么好的帖子就看不到了). 原文:http://my.oschina.net/amoshuang/blog/134199 在M ...