diff --git a/InkCanvasForClass.IccInkCanvas.Demo/InkCanvasForClass.IccInkCanvas.Demo.csproj b/InkCanvasForClass.IccInkCanvas.Demo/InkCanvasForClass.IccInkCanvas.Demo.csproj
index 5ce39ef..20c9fb1 100644
--- a/InkCanvasForClass.IccInkCanvas.Demo/InkCanvasForClass.IccInkCanvas.Demo.csproj
+++ b/InkCanvasForClass.IccInkCanvas.Demo/InkCanvasForClass.IccInkCanvas.Demo.csproj
@@ -94,5 +94,11 @@
+
+
+ {43929d8f-5630-4786-b75d-e203ea3e992f}
+ InkCanvasForClass.IccInkCanvas
+
+
\ No newline at end of file
diff --git a/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml b/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml
index 31d139f..a573bd0 100644
--- a/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml
+++ b/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml
@@ -4,9 +4,17 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:InkCanvasForClass.IccInkCanvas.Demo"
+ xmlns:iccInkCanvas="clr-namespace:InkCanvasForClass.IccInkCanvas;assembly=InkCanvasForClass.IccInkCanvas"
mc:Ignorable="d"
- Title="MainWindow" Height="450" Width="800">
+ Title="MainWindow" Height="850" Width="800">
-
+
+ IccInkCanvasDemo
+
+
+
+
+
+
diff --git a/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml.cs b/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml.cs
index 50a566a..b327b10 100644
--- a/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml.cs
+++ b/InkCanvasForClass.IccInkCanvas.Demo/MainWindow.xaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -12,6 +13,7 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
+using InkCanvasForClass.IccInkCanvas.Settings;
namespace InkCanvasForClass.IccInkCanvas.Demo {
///
@@ -21,5 +23,12 @@ namespace InkCanvasForClass.IccInkCanvas.Demo {
public MainWindow() {
InitializeComponent();
}
+
+ private void EditingModeChangeToNone_ButtonClick(object sender, RoutedEventArgs e) {
+ IccBoard.EditingMode = EditingMode.None;
+ }
+ private void EditingModeChangeToWriting_ButtonClick(object sender, RoutedEventArgs e) {
+ IccBoard.EditingMode = EditingMode.Writing;
+ }
}
}
diff --git a/InkCanvasForClass.IccInkCanvas/IccBoard.xaml b/InkCanvasForClass.IccInkCanvas/IccBoard.xaml
new file mode 100644
index 0000000..e12483e
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/IccBoard.xaml
@@ -0,0 +1,16 @@
+
+
+
+
+
diff --git a/InkCanvasForClass.IccInkCanvas/IccBoard.xaml.cs b/InkCanvasForClass.IccInkCanvas/IccBoard.xaml.cs
new file mode 100644
index 0000000..14eeb40
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/IccBoard.xaml.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using InkCanvasForClass.IccInkCanvas.Settings;
+
+namespace InkCanvasForClass.IccInkCanvas {
+ ///
+ /// IccBoard.xaml 的交互逻辑
+ ///
+ public partial class IccBoard : UserControl {
+
+ public BoardSettings BoardSettings { get; private set; } = new BoardSettings();
+
+ #region Properties
+
+ private bool _isEditingModePropertyAccessdByCodeBehind = false;
+ public EditingMode EditingMode {
+ get => (EditingMode)GetValue(EditingModeProperty);
+ set {
+ if (value == EditingMode.ShapeDrawing) throw new Exception("EditingMode.ShapeDrawing 不能被用户手动设定");
+ _isEditingModePropertyAccessdByCodeBehind = true;
+ SetValue(EditingModeProperty, value);
+ _isEditingModePropertyAccessdByCodeBehind = false;
+ UpdateEditingMode();
+ }
+ }
+ public static readonly System.Windows.DependencyProperty EditingModeProperty =
+ System.Windows.DependencyProperty.Register(
+ nameof(EditingMode),
+ typeof(EditingMode),
+ typeof(IccBoard),
+ new FrameworkPropertyMetadata(EditingMode.Writing,
+ FrameworkPropertyMetadataOptions.AffectsRender,
+ propertyChangedCallback: OnEditingModePropertyChanged));
+ private static void OnEditingModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
+ var iccboard = d as IccBoard;
+ if (iccboard != null && iccboard._isEditingModePropertyAccessdByCodeBehind) return;
+ iccboard?.UpdateEditingMode();
+ }
+
+ #endregion
+
+ #region EditingMode
+
+ private void UpdateEditingMode() {
+ if (EditingMode == EditingMode.None || EditingMode == EditingMode.NoneWithHitTest)
+ InkCanvas.EditingMode = InkCanvasEditingMode.None;
+ IsHitTestVisible = EditingMode != EditingMode.None;
+ if (EditingMode == EditingMode.Writing) InkCanvas.EditingMode = InkCanvasEditingMode.Ink;
+ }
+
+ #endregion
+
+ #region Events
+
+ private static readonly System.Windows.RoutedEvent EditingModeChangedEvent = EventManager.RegisterRoutedEvent(
+ name: "EditingModeChanged",
+ routingStrategy: RoutingStrategy.Bubble,
+ handlerType: typeof(System.Windows.RoutedEventHandler),
+ ownerType: typeof(IccBoard));
+ private static readonly System.Windows.RoutedEvent ActiveEditingModeChangedEvent = EventManager.RegisterRoutedEvent(
+ name: "ActiveEditingModeChanged",
+ routingStrategy: RoutingStrategy.Bubble,
+ handlerType: typeof(System.Windows.RoutedEventHandler),
+ ownerType: typeof(IccBoard));
+
+ public event System.Windows.RoutedEventHandler EditingModeChanged {
+ add => AddHandler(EditingModeChangedEvent, value);
+ remove => RemoveHandler(EditingModeChangedEvent, value);
+ }
+ public event System.Windows.RoutedEventHandler ActiveEditingModeChanged {
+ add => AddHandler(ActiveEditingModeChangedEvent, value);
+ remove => RemoveHandler(ActiveEditingModeChangedEvent, value);
+ }
+
+ private void RaiseEditingModeChangedEvent() {
+ RoutedEventArgs routedEventArgs = new RoutedEventArgs(routedEvent: EditingModeChangedEvent);
+ RaiseEvent(routedEventArgs);
+ }
+ private void RaiseActiveEditingModeChangedEvent() {
+ RoutedEventArgs routedEventArgs = new RoutedEventArgs(routedEvent: ActiveEditingModeChangedEvent);
+ RaiseEvent(routedEventArgs);
+ }
+
+ #endregion
+
+ public IccBoard() {
+ InitializeComponent();
+ }
+
+ private void IccInkCanvas_Loaded(object sender, RoutedEventArgs e) {
+ var ic = (IccInkCanvas)sender;
+
+ // 启动时自动修改 InkCanvas 的大小
+ var screenW = SystemParameters.PrimaryScreenWidth;
+ var screenH = SystemParameters.PrimaryScreenHeight;
+
+ var fullWidth = screenW * 257;
+ var fullHeight = screenH * 417;
+
+ var left = 0 - screenW * 128;
+ var top = 0 - screenH * 208;
+
+ ic.Width = fullWidth;
+ ic.Height = fullHeight;
+ Canvas.SetLeft(ic, left);
+ Canvas.SetTop(ic, top);
+
+ ic.DefaultDrawingAttributes.Width = BoardSettings.NibWidth;
+ ic.DefaultDrawingAttributes.Height = BoardSettings.NibHeight;
+ ic.DefaultDrawingAttributes.Color = BoardSettings.NibColor;
+
+ ic.BoardSettings = BoardSettings;
+ }
+
+ }
+}
diff --git a/InkCanvasForClass.IccInkCanvas/IccInkCanvas.cs b/InkCanvasForClass.IccInkCanvas/IccInkCanvas.cs
new file mode 100644
index 0000000..c2fd1aa
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/IccInkCanvas.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Input.StylusPlugIns;
+using System.Windows.Media;
+using InkCanvasForClass.IccInkCanvas.Settings;
+
+namespace InkCanvasForClass.IccInkCanvas {
+ class CustomDynamicRenderer : DynamicRenderer {
+
+ private Point prevPoint;
+
+ private IccInkCanvas _inkCanvas;
+
+ private List pointsList = new List();
+
+ private void ClearPointsList() {
+ pointsList.Clear();
+ }
+
+ private void PushPoint(StylusPoint point) {
+ pointsList.Add(point);
+ if (pointsList.Count > 15) {
+ pointsList.RemoveRange(0,pointsList.Count - 15);
+ }
+ }
+
+ public CustomDynamicRenderer(IccInkCanvas iccInkCanvas) {
+ _inkCanvas = iccInkCanvas;
+ }
+
+ protected override void OnStylusDown(RawStylusInput rawStylusInput) {
+ prevPoint = new Point(double.NegativeInfinity, double.NegativeInfinity);
+ ClearPointsList();
+ var pts = rawStylusInput.GetStylusPoints();
+ if (pts.Count == 1) {
+ PushPoint(pts.Single());
+ } else if (pts.Count > 1) {
+ PushPoint(pts[pts.Count-1]);
+ }
+ Trace.WriteLine(pointsList.Count);
+ base.OnStylusDown(rawStylusInput);
+ }
+
+ protected override void OnStylusMove(RawStylusInput rawStylusInput) {
+ base.OnStylusMove(rawStylusInput);
+ var pts = rawStylusInput.GetStylusPoints();
+ if (pts.Count == 1) {
+ PushPoint(pts.Single());
+ } else if (pts.Count > 1) {
+ PushPoint(pts[pts.Count-1]);
+ }
+ Trace.WriteLine(pointsList.Count);
+ }
+
+ protected override void OnDraw(DrawingContext drawingContext,
+ StylusPointCollection stylusPoints,
+ Geometry geometry, Brush fillBrush) {
+ if (_inkCanvas.BoardSettings.StrokeNibStyle == StrokeNibStyle.Beautiful) {
+ try {
+ var sp = new StylusPointCollection();
+ var n = pointsList.Count - 1;
+ var pressure = 0.1;
+ var x = 10;
+ if (n == 1) return;
+ if (n >= x) {
+ for (var i = 0; i < n - x; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)0.5;
+ point.X = pointsList[i].X;
+ point.Y = pointsList[i].Y;
+ sp.Add(point);
+ }
+
+ for (var i = n - x; i <= n; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)((0.5 - pressure) * (n - i) / x + pressure);
+ point.X = pointsList[i].X;
+ point.Y = pointsList[i].Y;
+ sp.Add(point);
+ }
+ } else {
+ for (var i = 0; i <= n; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)(0.4 * (n - i) / n + pressure);
+ point.X = pointsList[i].X;
+ point.Y = pointsList[i].Y;
+ sp.Add(point);
+ }
+ }
+
+ var da = DrawingAttributes.Clone();
+ da.Width -= 0.5;
+ da.Height -= 0.5;
+ var stk = new Stroke(sp, da);
+ stk.Draw(drawingContext);
+ } catch {}
+ } else {
+ base.OnDraw(drawingContext, stylusPoints, geometry, fillBrush);
+ }
+
+ }
+ }
+
+ public class IccInkCanvas : InkCanvas {
+
+ CustomDynamicRenderer customDynamicRenderer;
+
+ public BoardSettings BoardSettings { get; set; } = new BoardSettings();
+
+ public IccInkCanvas() {
+ customDynamicRenderer = new CustomDynamicRenderer(this);
+ DynamicRenderer = customDynamicRenderer;
+
+ // 通过反射移除InkCanvas自带的默认 Delete按键事件
+ var commandBindingsField =
+ typeof(CommandManager).GetField("_classCommandBindings", BindingFlags.NonPublic | BindingFlags.Static);
+ var bnds = commandBindingsField.GetValue(null) as HybridDictionary;
+ var inkCanvasBindings = bnds[typeof(InkCanvas)] as CommandBindingCollection;
+ var enumerator = inkCanvasBindings.GetEnumerator();
+ while (enumerator.MoveNext()) {
+ var item = (CommandBinding)enumerator.Current;
+ if (item.Command == ApplicationCommands.Delete) {
+ var executedField =
+ typeof(CommandBinding).GetField("Executed", BindingFlags.NonPublic | BindingFlags.Instance);
+ var canExecuteField =
+ typeof(CommandBinding).GetField("CanExecute", BindingFlags.NonPublic | BindingFlags.Instance);
+ executedField.SetValue(item, new ExecutedRoutedEventHandler((sender, args) => { }));
+ canExecuteField.SetValue(item, new CanExecuteRoutedEventHandler((sender, args) => { }));
+ }
+ }
+
+ // 为IccInkCanvas注册自定义的 Delete按键Command并Invoke OnDeleteCommandFired。
+ CommandManager.RegisterClassCommandBinding(typeof(IccInkCanvas), new CommandBinding(ApplicationCommands.Delete,
+ (sender, args) => {
+ DeleteKeyCommandFired?.Invoke(this, new RoutedEventArgs());
+ }, (sender, args) => {
+ args.CanExecute = GetSelectedStrokes().Count != 0;
+ }));
+ }
+
+ protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e) {
+ IccStroke customStroke = new IccStroke(e.Stroke.StylusPoints, e.Stroke.DrawingAttributes);
+ if (e.Stroke is IccStroke) {
+ this.Strokes.Add(e.Stroke);
+ } else {
+ this.Strokes.Remove(e.Stroke);
+ this.Strokes.Add(customStroke);
+ }
+
+ if (BoardSettings.StrokeNibStyle == StrokeNibStyle.Beautiful) {
+ try {
+ var stylusPoints = new StylusPointCollection();
+ var n = customStroke.StylusPoints.Count - 1;
+ var pressure = 0.1;
+ var x = 10;
+ if (n == 1) return;
+ if (n >= x) {
+ for (var i = 0; i < n - x; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)0.5;
+ point.X = customStroke.StylusPoints[i].X;
+ point.Y = customStroke.StylusPoints[i].Y;
+ stylusPoints.Add(point);
+ }
+
+ for (var i = n - x; i <= n; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)((0.5 - pressure) * (n - i) / x + pressure);
+ point.X = customStroke.StylusPoints[i].X;
+ point.Y = customStroke.StylusPoints[i].Y;
+ stylusPoints.Add(point);
+ }
+ }
+ else {
+ for (var i = 0; i <= n; i++) {
+ var point = new StylusPoint();
+
+ point.PressureFactor = (float)(0.4 * (n - i) / n + pressure);
+ point.X = customStroke.StylusPoints[i].X;
+ point.Y = customStroke.StylusPoints[i].Y;
+ stylusPoints.Add(point);
+ }
+ }
+
+ customStroke.StylusPoints = stylusPoints;
+ } catch { }
+ }
+
+ InkCanvasStrokeCollectedEventArgs args =
+ new InkCanvasStrokeCollectedEventArgs(customStroke);
+ base.OnStrokeCollected(args);
+ }
+
+ public event EventHandler DeleteKeyCommandFired;
+ }
+}
diff --git a/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml b/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml
deleted file mode 100644
index 2cace9c..0000000
--- a/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
diff --git a/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml.cs b/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml.cs
deleted file mode 100644
index 7a8f8f7..0000000
--- a/InkCanvasForClass.IccInkCanvas/IccInkCanvas.xaml.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace InkCanvasForClass.IccInkCanvas {
- ///
- /// IccInkCanvas.xaml 的交互逻辑
- ///
- public partial class IccInkCanvas : UserControl {
- public IccInkCanvas() {
- InitializeComponent();
- }
- }
-}
diff --git a/InkCanvasForClass.IccInkCanvas/IccStroke.cs b/InkCanvasForClass.IccInkCanvas/IccStroke.cs
new file mode 100644
index 0000000..05d1a9a
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/IccStroke.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+
+namespace InkCanvasForClass.IccInkCanvas {
+
+ static class ToPointsHelper {
+ public static Point[] ToPoints(this IEnumerable stylusPoints)
+ {
+ List pointList = new List();
+ foreach (StylusPoint stylusPoint in stylusPoints)
+ pointList.Add(stylusPoint.ToPoint());
+ return pointList.ToArray();
+ }
+ }
+
+ public enum ShapeDrawingType {
+ Line,
+ DottedLine,
+ DashedLine,
+ ArrowOneSide,
+ ArrowTwoSide,
+ Rectangle,
+ Ellipse,
+ PieEllipse,
+ Triangle,
+ RightTriangle,
+ Diamond,
+ Parallelogram,
+ FourLine,
+ Staff,
+ Axis2D,
+ Axis2DA,
+ Axis2DB,
+ Axis2DC,
+ Axis3D,
+ Hyperbola,
+ HyperbolaF,
+ Parabola,
+ ParabolaA,
+ ParabolaAF,
+ Cylinder,
+ Cube,
+ Cone,
+ EllipseC,
+ RectangleC
+ }
+
+ public static class ShapeDrawingHelper {
+
+ ///
+ /// 根据给定的两个点计算角度
+ ///
+ ///
+ ///
+ ///
+ public static double CaculateRotateAngleByGivenTwoPoints(Point firstPoint, Point lastPoint) {
+ var vec1 = new double[] {
+ lastPoint.X - firstPoint.X ,
+ lastPoint.Y - firstPoint.Y
+ };
+ var vec_base = new double[] { 0, firstPoint.Y };
+ var cosine = (vec_base[0] * vec1[0] + vec_base[1] * vec1[1]) /
+ (Math.Sqrt(Math.Pow(vec_base[0],2) + Math.Pow(vec_base[1],2)) *
+ Math.Sqrt(Math.Pow(vec1[0],2) + Math.Pow(vec1[1],2)));
+ var angle = Math.Acos(cosine);
+ var isIn2And3Quadrant = lastPoint.X <= firstPoint.X;
+ var rotateAngle = Math.Round(180 + 180 * (angle / Math.PI) * (isIn2And3Quadrant ? 1 : -1), 0);
+ return rotateAngle;
+ }
+
+
+ public static List DistributePointsOnLine(Point start, Point end, double interval=16) {
+ List points = new List();
+
+ double dx = end.X - start.X;
+ double dy = end.Y - start.Y;
+ double distance = Math.Sqrt(dx * dx + dy * dy);
+ int numPoints = (int)(distance / interval);
+
+ for (int i = 0; i <= numPoints; i++) {
+ double ratio = (interval * i) / distance;
+ double x = start.X + ratio * dx;
+ double y = start.Y + ratio * dy;
+ points.Add(new Point(x, y));
+ }
+
+ return points;
+ }
+
+ public class ArrowLineConfig {
+ public int ArrowWidth { get; set; } = 20;
+ public int ArrowHeight { get; set; } = 7;
+ }
+
+ }
+
+ public class IccStroke : Stroke {
+
+ public IccStroke(StylusPointCollection stylusPoints, DrawingAttributes drawingAttributes)
+ : base(stylusPoints, drawingAttributes) { }
+
+ public static Guid StrokeShapeTypeGuid = new Guid("6537b29c-557f-487f-800b-cb30a8f1de78");
+ public static Guid StrokeIsShapeGuid = new Guid("40eff5db-9346-4e42-bd46-7b0eb19d0018");
+
+ public StylusPointCollection RawStylusPointCollection { get; set; }
+
+ public ShapeDrawingHelper.ArrowLineConfig ArrowLineConfig { get; set; } =
+ new ShapeDrawingHelper.ArrowLineConfig();
+
+ ///
+ /// 根据这个属性判断当前 Stroke 是否是原始输入
+ ///
+ public bool IsRawStylusPoints = true;
+
+ ///
+ /// 根据这个属性决定在绘制 Stroke 时是否需要在直线形状中,在两点构成直线上分布点,用于墨迹的范围框选。
+ ///
+ public bool IsDistributePointsOnLineShape = true;
+
+ ///
+ /// 指示该墨迹是否来自一个完整墨迹被擦除后的一部分墨迹,仅用于形状墨迹。
+ ///
+ public bool IsErasedStrokePart = false;
+
+ // 自定义的墨迹渲染
+ protected override void DrawCore(DrawingContext drawingContext,
+ DrawingAttributes drawingAttributes) {
+ if (!(this.ContainsPropertyData(StrokeIsShapeGuid) &&
+ (bool)this.GetPropertyData(StrokeIsShapeGuid) == true)) {
+ base.DrawCore(drawingContext, drawingAttributes);
+ return;
+ }
+
+ if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DashedLine ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.Line ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowOneSide ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowTwoSide) {
+ if (StylusPoints.Count < 2) {
+ base.DrawCore(drawingContext, drawingAttributes);
+ return;
+ }
+
+ var pts = new List(this.StylusPoints.ToPoints());
+ if (IsDistributePointsOnLineShape && (
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DashedLine ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.Line ||
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine) && IsRawStylusPoints) {
+ IsRawStylusPoints = false;
+ RawStylusPointCollection = StylusPoints.Clone();
+ var pointList = new List { new Point(StylusPoints[0].X, StylusPoints[0].Y) };
+ pointList.AddRange(ShapeDrawingHelper.DistributePointsOnLine(new Point(StylusPoints[0].X, StylusPoints[0].Y),new Point(StylusPoints[1].X, StylusPoints[1].Y)));
+ pointList.Add(new Point(StylusPoints[1].X, StylusPoints[1].Y));
+ StylusPoints = new StylusPointCollection(pointList);
+ }
+ StreamGeometry geometry = new StreamGeometry();
+ using (StreamGeometryContext ctx = geometry.Open()) {
+ ctx.BeginFigure(pts[0], false , false);
+ pts.RemoveAt(0);
+ ctx.PolyLineTo(pts,true, true);
+ }
+ var pen = new Pen(new SolidColorBrush(DrawingAttributes.Color),
+ (drawingAttributes.Width + drawingAttributes.Height) / 2) {
+ DashCap = PenLineCap.Round,
+ StartLineCap = PenLineCap.Round,
+ EndLineCap = PenLineCap.Round,
+ };
+ if ((int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.Line &&
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.ArrowOneSide &&
+ (int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)ShapeDrawingType.ArrowTwoSide)
+ pen.DashStyle = (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.DottedLine ? DashStyles.Dot : DashStyles.Dash;
+
+ if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)ShapeDrawingType.ArrowOneSide && IsRawStylusPoints) {
+ IsRawStylusPoints = false;
+ pts = new List(this.StylusPoints.ToPoints());
+ RawStylusPointCollection = StylusPoints.Clone();
+ double w = ArrowLineConfig.ArrowWidth, h = ArrowLineConfig.ArrowHeight;
+ var theta = Math.Atan2(pts[0].Y - pts[1].Y, pts[0].X - pts[1].X);
+ var sint = Math.Sin(theta);
+ var cost = Math.Cos(theta);
+ var pointList = new List {
+ new Point(pts[0].X, pts[0].Y),
+ };
+ if (IsDistributePointsOnLineShape) pointList.AddRange(ShapeDrawingHelper.DistributePointsOnLine(new Point(pts[0].X, pts[0].Y),new Point(pts[1].X, pts[1].Y)));
+ pointList.AddRange(new List {
+ new Point(pts[1].X, pts[1].Y),
+ new Point(pts[1].X + (w * cost - h * sint), pts[1].Y + (w * sint + h * cost)),
+ new Point(pts[1].X, pts[1].Y),
+ new Point(pts[1].X + (w * cost + h * sint), pts[1].Y - (h * cost - w * sint)),
+ });
+ StylusPoints = new StylusPointCollection(pointList);
+ var _pts = new List(this.StylusPoints.ToPoints());
+ using (StreamGeometryContext ctx = geometry.Open()) {
+ ctx.BeginFigure(_pts[0], false , false);
+ _pts.RemoveAt(0);
+ ctx.PolyLineTo(_pts,true, true);
+ }
+ drawingContext.DrawGeometry(new SolidColorBrush(DrawingAttributes.Color),pen, geometry);
+ return;
+
+ }
+ drawingContext.DrawGeometry(new SolidColorBrush(Colors.Transparent),pen, geometry);
+ }
+
+ }
+ }
+}
diff --git a/InkCanvasForClass.IccInkCanvas/InkCanvasForClass.IccInkCanvas.csproj b/InkCanvasForClass.IccInkCanvas/InkCanvasForClass.IccInkCanvas.csproj
index 2a13bcd..2bf882d 100644
--- a/InkCanvasForClass.IccInkCanvas/InkCanvasForClass.IccInkCanvas.csproj
+++ b/InkCanvasForClass.IccInkCanvas/InkCanvasForClass.IccInkCanvas.csproj
@@ -48,9 +48,12 @@
-
- IccInkCanvas.xaml
+
+
+ IccBoard.xaml
+
+
Code
@@ -64,6 +67,8 @@
Settings.settings
True
+
+
ResXFileCodeGenerator
Resources.Designer.cs
@@ -74,10 +79,11 @@
-
+
Designer
MSBuild:Compile
+
\ No newline at end of file
diff --git a/InkCanvasForClass.IccInkCanvas/README.md b/InkCanvasForClass.IccInkCanvas/README.md
new file mode 100644
index 0000000..0ff1d63
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/README.md
@@ -0,0 +1,6 @@
+# IccInkCanvas
+
+`InkCanvasForClass.IccInkCanvas`
+
+## 方法
+
diff --git a/InkCanvasForClass.IccInkCanvas/Settings/BoardSettings.cs b/InkCanvasForClass.IccInkCanvas/Settings/BoardSettings.cs
new file mode 100644
index 0000000..8b23815
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/Settings/BoardSettings.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+
+namespace InkCanvasForClass.IccInkCanvas.Settings {
+ public class BoardSettings {
+ public BoardSettings() {}
+
+ ///
+ /// 笔尖长度
+ ///
+ public double NibWidth { get; set; } = 4.00;
+
+ ///
+ /// 笔尖高度
+ ///
+ public double NibHeight { get; set; } = 4.00;
+
+ ///
+ /// 笔尖大小,适合笔尖类型为普通笔时使用
+ ///
+ public double NibSize {
+ get => (NibWidth + NibHeight) / 2;
+ set => NibWidth = NibHeight = value;
+ }
+
+ public NibType NibType { get; set; } = NibType.Default;
+
+ ///
+ /// 笔尖颜色
+ ///
+ public Color NibColor { get; set; } = Colors.Black;
+
+ ///
+ /// 笔锋样式类型,默认有笔锋
+ ///
+ public StrokeNibStyle StrokeNibStyle { get; set; } = StrokeNibStyle.Beautiful;
+ }
+}
diff --git a/InkCanvasForClass.IccInkCanvas/Settings/EditingMode.cs b/InkCanvasForClass.IccInkCanvas/Settings/EditingMode.cs
new file mode 100644
index 0000000..0e247e2
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/Settings/EditingMode.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InkCanvasForClass.IccInkCanvas.Settings {
+
+ ///
+ /// IccBoard的编辑模式
+ ///
+ public enum EditingMode {
+ ///
+ /// 仅显示墨迹,不会接收任何输入事件,没有HitTest
+ ///
+ None,
+ ///
+ /// 仅显示墨迹,不会接收任何输入事件,有HitTest
+ ///
+ NoneWithHitTest,
+ ///
+ /// 书写模式,该模式下允许临时切换到橡皮擦模式
+ ///
+ Writing,
+ ///
+ /// 墨迹擦模式
+ ///
+ StrokeErasing,
+ ///
+ /// 板擦模式
+ ///
+ GeometryErasing,
+ ///
+ /// 区域擦除模式
+ ///
+ AreaErasing,
+ ///
+ /// 墨迹选择模式
+ ///
+ Select,
+ ///
+ /// 仅显示墨迹,仅接受手势输入
+ ///
+ Gestures,
+ ///
+ /// 形状绘制模式,该模式不能被用户直接设置
+ ///
+ ShapeDrawing,
+ ///
+ /// 漫游模式
+ ///
+ RoamingMode
+ }
+}
diff --git a/InkCanvasForClass.IccInkCanvas/Settings/Nib.cs b/InkCanvasForClass.IccInkCanvas/Settings/Nib.cs
new file mode 100644
index 0000000..c0960e7
--- /dev/null
+++ b/InkCanvasForClass.IccInkCanvas/Settings/Nib.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InkCanvasForClass.IccInkCanvas.Settings {
+
+ ///
+ /// 定义了笔尖类型
+ ///
+ public enum NibType {
+ ///
+ /// 默认笔
+ ///
+ Default,
+ ///
+ /// 荧光笔
+ ///
+ Highlighter
+ }
+
+ ///
+ /// 笔锋样式
+ ///
+ public enum StrokeNibStyle {
+ ///
+ /// 无笔锋
+ ///
+ Solid,
+ ///
+ /// 有笔锋,基于固定点集算法计算
+ ///
+ Beautiful
+ }
+}