using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows;
using System.Xml.Serialization;
using XHandler.Class;
using System.ComponentModel;
using XHandler.View.Consumables;
using XImagingXhandler.XDAL;
using XHandler.View.ManualPick;
using XCommon.Tip;
using XCommon.Image;
namespace XHandler.Controls.DrawCanvas
{
[ContentProperty]
public sealed class DrawingCanvas : Canvas
{
public int ID = 1;
///
/// 确定
///
public static readonly RoutedEvent AddPointRoutedEvent =
EventManager.RegisterRoutedEvent("AddPointEvent", RoutingStrategy.Bubble, typeof(CustomEvent.CustomRoutedEventHandler), typeof(DrawingCanvas));
[Description("AddPointEvent")]
public event CustomEvent.CustomRoutedEventHandler AddPointEvent
{
add
{
this.AddHandler(AddPointRoutedEvent, value);
}
remove
{
this.RemoveHandler(AddPointRoutedEvent, value);
}
}
private void RaiseAddPointEvent(PointData data)
{
CustomRoutedEventArgs arg = new CustomRoutedEventArgs(AddPointRoutedEvent, data);
this.RaiseEvent(arg);
}
public DrawingCanvas()
{
this.ClipToBounds = true;
this.Focusable = true;
this.OriginalCursor = Cursors.Arrow;
this.squareCursor = false;
this.SelectBackgroundPen = new Pen(Brushes.White, 1);
this.SelectPen = new Pen(Brushes.Black, 1) { DashStyle = new DashStyle(new Double[] { 4 }, 0) };
this.Loaded += delegate
{
this.Focus();
this.drawViewer = Utilities.FindVisualParent(this);
};
}
#region 可视化
private List visuals = new List();
protected override Int32 VisualChildrenCount => visuals.Count + Children.Count;
protected override Visual GetVisualChild(Int32 index)
{
if (index < visuals.Count)
return visuals[index];
else
return Children[index - visuals.Count];
}
public void AddVisual(DrawGeometryBase visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public void Insert(Int32 index, Visual visual)
{
visuals.Insert(index, visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public void MovoToHead(Visual visual)
{
var index = visuals.IndexOf(visual);
if (index <= 0)
return;
visuals.RemoveAt(index);
visuals.Insert(0, visual);
}
public void DeleteVisual(Visual visual)
{
visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
public Visual GetVisual(int id)
{
return visuals.FirstOrDefault(it => ((DrawGeometryBase)it).ID == id);
}
public DrawingVisual GetVisual(Point point)
{
var hitResult = VisualTreeHelper.HitTest(this, point);
if (hitResult != null)
{
return hitResult.VisualHit as DrawingVisual;
}
else
{
return null;
}
}
#endregion
#region 依赖属性
public static readonly DependencyProperty BrushProperty = DependencyProperty.Register("Brush", typeof(SolidColorBrush), typeof(DrawingCanvas), new PropertyMetadata(Brushes.Black, OnBrushPropertyChanged));
private static void OnBrushPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DrawingCanvas)d).UpdateCursor();
}
///
/// 画刷颜色
///
public SolidColorBrush Brush { get => (SolidColorBrush)this.GetValue(BrushProperty); set => this.SetValue(BrushProperty, value); }
public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(UInt32), typeof(DrawingCanvas), new PropertyMetadata(1u, OnStrokeThicknessPropertyChanged));
private static void OnStrokeThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((DrawingCanvas)d).UpdateCursor();
}
///
/// 画刷宽度
///
public UInt32 StrokeThickness { get => (UInt32)this.GetValue(StrokeThicknessProperty); set => this.SetValue(StrokeThicknessProperty, value); }
public static readonly DependencyProperty DrawingToolTypeProperty = DependencyProperty.Register("DrawingToolType", typeof(DrawToolType), typeof(DrawingCanvas), new PropertyMetadata(DrawToolType.Pointer, OnDrawingToolTypePropertyChanged));
private static void OnDrawingToolTypePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var drawing = (DrawingCanvas)d;
if (!drawing.IsKeyboardFocused)
drawing.Focus();
drawing.UpdateCursor();
}
///
/// 当前的画图工具
///
public DrawToolType DrawingToolType { get => (DrawToolType)this.GetValue(DrawingToolTypeProperty); set => this.SetValue(DrawingToolTypeProperty, value); }
public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(typeof(DrawingCanvas), new FrameworkPropertyMetadata(12d, FrameworkPropertyMetadataOptions.Inherits));
///
/// 文本大小
///
public Double FontSize { get => (Double)this.GetValue(FontSizeProperty); set => this.SetValue(FontSizeProperty, value); }
public static readonly DependencyProperty ZoomProperty = DrawingCanvasViewer.ZoomProperty.AddOwner(typeof(DrawingCanvas), new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnZoomPropertyChanged)));
private static void OnZoomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!Double.IsNaN((Double)e.NewValue))
((DrawingCanvas)d).UpdateCursor();
}
///
/// X轴缩放
///
public Double Zoom { get => (Double)this.GetValue(ZoomProperty); set => this.SetValue(ZoomProperty, value); }
#endregion
#region 鼠标键盘事件
protected override void OnMouseEnter(MouseEventArgs e)
{
IDrawTool tool;
var point = e.GetPosition(this);
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == 0 && tool.CanTouchEnter && (e.Handled = tool.OnTouchEnter(point)))
return;
}
}
protected override void OnMouseLeave(MouseEventArgs e)
{
lastPoint = null;
IDrawTool tool;
var point = e.GetPosition(this);
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == 0 && tool.CanTouchLeave && (e.Handled = tool.OnTouchLeave(point)))
return;
}
}
#region 鼠标左击
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
if (!this.IsKeyboardFocused)
this.Focus();
if (this.canDragStart)
{
lastPoint = e.GetPosition(this.drawViewer);
e.Handled = true;
return;
}
IDrawTool tool;
Point point = e.GetPosition(this);
//for (var i = workingDrawTools.Count - 1; i >= 0; i--)
//{
// tool = workingDrawTools[i];
// if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
// return;
//}
//tool = CreateDrawingTool();
//if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
// return;
MouseLeftButtonDown(point);
if (this.canDragStart)
{
lastPoint = e.GetPosition(this);
e.Handled = true;
return;
}
}
public void MouseLeftButtonDown(Point point)
{
IDrawTool tool = null;
//for (var i = workingDrawTools.Count - 1; i >= 0; i--)
//{
// tool = workingDrawTools[i];
// if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
// return;
//}
tool = CreateDrawingTool();
//if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
// return;
tool.OnTouchDown(0, point);
}
#endregion
#region 鼠标右击
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
//lastPoint = null;
//IDrawTool tool;
Point point = e.GetPosition(this);
//for (var i = workingDrawTools.Count - 1; i >= 0; i--)
//{
// tool = workingDrawTools[i];
// if (tool.TouchId == 0 && tool.CanTouchUp && (e.Handled = tool.OnTouchLeave(point)))
// {
// PointData pt = new PointData();
// EllipseDrawTool ellipseDrawTool = (EllipseDrawTool)tool;
// //if (ellipseDrawTool.radiusX == 0 || ellipseDrawTool.radiusY == 0)
// // return;
// pt.id = this.ID - 1;
// pt.point = new Point(ellipseDrawTool.center.X, ellipseDrawTool.center.Y);
// pt.diameter = Math.Min(ellipseDrawTool.radiusX * 2, ellipseDrawTool.radiusY * 2);
// RaiseAddPointEvent(pt);
// return;
// }
//}
MouseLeftButtonUp(point);
}
public void MouseLeftButtonUp(Point point, string coordinateMachine = "")
{
IDrawTool tool = null;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
//if (tool.TouchId == 0 && tool.CanTouchUp && (e.Handled = tool.OnTouchLeave(point)))
{
tool.OnTouchLeave(point);
PointData pt = new PointData();
EllipseDrawTool ellipseDrawTool = (EllipseDrawTool)tool;
pt.id = this.ID - 1;
pt.point = new Point(ellipseDrawTool.center.X, ellipseDrawTool.center.Y);
pt.diameter = Math.Min(ellipseDrawTool.radiusX * 2, ellipseDrawTool.radiusY * 2);
pt.coordinate_machine = coordinateMachine;
RaiseAddPointEvent(pt);
return;
}
}
lastPoint = null;
}
#endregion
#region 在特定的点位画上文字,表示被删除
public void DrawTextShowDeletedState(Point point)
{
IDrawTool tool= CreateDrawingTool();
this.Brush = Brushes.Red;
tool.OnTouchDown(0, point);
SolidColorBrush mybtn1_Brush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 255, 165, 0));
this.Brush = mybtn1_Brush;
}
#endregion
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (this.canDragMove)
{
var drawPoint = e.GetPosition(this.drawViewer);
var dx = lastPoint.Value.X - drawPoint.X;
var dy = lastPoint.Value.Y - drawPoint.Y;
this.drawViewer.ScrollBy(dx, dy);
lastPoint = drawPoint;
e.Handled = true;
return;
}
var point = e.GetPosition(this);
if (point.X < 0 || point.Y < 0 || point.X > this.ActualWidth || point.Y > this.ActualHeight)
return;
IDrawTool tool;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == 0 && tool.CanTouchMove && (e.Handled = tool.OnTouchMove(e.GetPosition(this))))
return;
}
}
}
protected override void OnKeyDown(KeyEventArgs e)
{
IDrawTool tool;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.CanKeyDown && (e.Handled = tool.OnKeyDown(e.Key)))
return;
}
if (e.Key == Key.Space)
{
this.OriginalCursor = DrawCursors.Hand;
this.squareCursor = false;
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
IDrawTool tool;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.CanKeyUp && (e.Handled = tool.OnKeyUp(e.Key)))
return;
}
if (e.Key == Key.Space)
this.UpdateCursor();
}
#endregion
#region 触摸事件
protected override void OnTouchEnter(TouchEventArgs e)
{
IDrawTool tool;
var point = e.GetTouchPoint(this).Position;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == e.TouchDevice.Id && tool.CanTouchEnter && (e.Handled = tool.OnTouchEnter(point)))
return;
}
}
protected override void OnTouchLeave(TouchEventArgs e)
{
lastPoint = null;
IDrawTool tool;
var point = e.GetTouchPoint(this).Position;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == e.TouchDevice.Id && tool.CanTouchLeave && (e.Handled = tool.OnTouchLeave(point)))
return;
}
}
protected override void OnTouchDown(TouchEventArgs e)
{
if (!this.IsKeyboardFocused)
this.Focus();
if (this.canDragStart)
{
lastPoint = e.GetTouchPoint(this.drawViewer).Position;
e.Handled = true;
return;
}
IDrawTool tool;
var point = e.GetTouchPoint(this).Position;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
return;
}
tool = CreateDrawingTool();
if (tool.CanTouchDown && (e.Handled = tool.OnTouchDown(0, point)))
return;
if (this.canDragStart)
{
lastPoint = point;
e.Handled = true;
return;
}
}
protected override void OnTouchMove(TouchEventArgs e)
{
if (this.canDragMove)
{
var drawPoint = e.GetTouchPoint(this.drawViewer).Position;
var dx = lastPoint.Value.X - drawPoint.X;
var dy = lastPoint.Value.Y - drawPoint.Y;
this.drawViewer.ScrollBy(dx, dy);
lastPoint = drawPoint;
e.Handled = true;
return;
}
var point = e.GetTouchPoint(this).Position;
if (point.X < 0 || point.Y < 0 || point.X > this.ActualWidth || point.Y > this.ActualHeight)
return;
IDrawTool tool;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == 0 && tool.CanTouchMove && (e.Handled = tool.OnTouchMove(point)))
return;
}
}
protected override void OnTouchUp(TouchEventArgs e)
{
lastPoint = null;
IDrawTool tool;
var point = e.GetTouchPoint(this).Position;
for (var i = workingDrawTools.Count - 1; i >= 0; i--)
{
tool = workingDrawTools[i];
if (tool.TouchId == 0 && tool.CanTouchUp && (e.Handled = tool.OnTouchUp(point)))
return;
}
}
#endregion
#region 公开方法
public void Clear()
{
foreach (var visual in visuals)
{
base.RemoveLogicalChild(visual);
base.RemoveVisualChild(visual);
}
this.visuals.Clear();
this.Children.Clear();
this.workingDrawTools.Clear();
}
public IEnumerable GetDrawGeometries()
{
return visuals.OfType().Where(q => q.IsFinish);
}
public void AddWorkingDrawTool(IDrawTool drawTool)
{
this.workingDrawTools.Add(drawTool);
}
public void DeleteWorkingDrawTool(IDrawTool drawTool)
{
this.workingDrawTools.Remove(drawTool);
}
///
/// 转为图片
///
///
///
///
///
///
public BitmapFrame ToBitmapFrame(Int32 pixelWidth, Int32 pixelHeight, Dpi dpi, ImageSource image = null)
{
var visual = GetDrawingVisual(pixelWidth, pixelHeight, dpi, image);
if (visual == null)
return null;
var renderBitmap = new RenderTargetBitmap(pixelWidth, pixelHeight, dpi.DpiX, dpi.DpiY, PixelFormats.Pbgra32);
renderBitmap.Render(visual);
return BitmapFrame.Create(renderBitmap);
}
///
/// 打印
///
///
///
///
///
public void Print(Int32 pixelWidth, Int32 pixelHeight, Dpi dpi, ImageSource image = null)
{
//var visual = GetDrawingVisual(pixelWidth, pixelHeight, dpi, image);
//if (visual == null)
// return;
//var printDlg = new PrintDialog();
//if ((Boolean)printDlg.ShowDialog())
//{
// var l = Math.Max(pixelWidth, pixelHeight);
// var s = Math.Min(pixelWidth, pixelHeight);
// var sizeL = Math.Max(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight);
// var sizeS = Math.Min(printDlg.PrintableAreaWidth, printDlg.PrintableAreaHeight);
// var zoom = Math.Min(sizeL / l, sizeS / s);
// visual.Transform = new ScaleTransform(zoom, zoom);
// if (pixelWidth != pixelHeight && (pixelWidth > pixelHeight ^ printDlg.PrintableAreaWidth > printDlg.PrintableAreaHeight))
// printDlg.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
// printDlg.PrintVisual(visual, nameof(DrawingCanvas));
//}
}
public void Save(String filepath)
{
var serializer = new DrawGeometrySerializer
{
Geometries = this.GetDrawGeometries().Select(q => q.ToSerializer()).ToArray()
};
var xml = new XmlSerializer(typeof(DrawGeometrySerializer));
using (var fs = new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.None))
{
xml.Serialize(fs, serializer);
}
}
public void Load(String filepath)
{
var xml = new XmlSerializer(typeof(DrawGeometrySerializer));
using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var serializer = (DrawGeometrySerializer)xml.Deserialize(fs);
this.Clear();
foreach (var draw in serializer.Geometries)
{
this.AddVisual(draw.Deserialize(this));
}
}
}
#endregion
#region 私有方法
///
/// 创建画图工具
///
///
///
private IDrawTool CreateDrawingTool()
{
switch (DrawingToolType)
{
//case DrawToolType.Pointer:
// return new PointerDrawTool(this);
//case DrawToolType.Pen:
// return new PenDrawTool(this);
//case DrawToolType.Eraser:
// return new EraserDrawTool(this);
//case DrawToolType.Line:
// return new LineDrawTool(this);
//case DrawToolType.Arrow:
// return new ArrowDrawTool(this);
//case DrawToolType.Ranging:
// return new RangingDrawTool(this);
//case DrawToolType.Rectangle:
// return new RectangleDrawTool(this);
case DrawToolType.Ellipse:
return new EllipseDrawTool(this);
//case DrawToolType.Angle:
// return new AngleDrawTool(this);
//case DrawToolType.Polyline:
// return new PolylineDrawTool(this);
//case DrawToolType.Curve:
// return new CurveDrawTool(this);
//case DrawToolType.Polygon:
// return new PolygonDrawTool(this);
//case DrawToolType.ClosedCurve:
// return new ClosedCurveDrawTool(this);
//case DrawToolType.Area:
// return new AreaDrawTool(this);
//case DrawToolType.Text:
// return new TextDrawTool(this);
default:
throw new ArgumentOutOfRangeException("不支持画图工具" + DrawingToolType);
}
}
private void UpdateCursor()
{
switch (this.DrawingToolType)
{
case DrawToolType.Pointer:
this.OriginalCursor = Cursors.Arrow;
this.squareCursor = false;
break;
case DrawToolType.Text:
this.OriginalCursor = Cursors.IBeam;
this.squareCursor = false;
break;
case DrawToolType.Ellipse:
this.OriginalCursor = Cursors.Cross;
this.squareCursor = false;
break;
default:
if ((squareCursor && cursorLength == StrokeThickness && cursorZoom == Zoom) || Double.IsNaN(StrokeThickness) || Double.IsNaN(Zoom))
break;
var w = (UInt32)Math.Max(1, StrokeThickness * Zoom);
var h = (UInt32)Math.Max(1, StrokeThickness * Zoom);
var border = (UInt32)Math.Max(1, 2 * Math.Min(1, Zoom));
this.OriginalCursor = DrawCursors.CreateBmpCursor(w, h, border, Brush);
this.squareCursor = true;
this.cursorLength = StrokeThickness;
this.cursorZoom = Zoom;
break;
}
}
private DrawingVisual GetDrawingVisual(Int32 pixelWidth, Int32 pixelHeight, Dpi dpi, ImageSource image = null)
{
var root = new DrawingVisual();
var dc = root.RenderOpen();
var drawGeometries = this.GetDrawGeometries();
if (image != null)
dc.DrawImage(image, new Rect(new Size(pixelWidth * dpi.Px2WpfX, pixelHeight * dpi.Px2WpfY)));
foreach (var draw in drawGeometries)
{
dc.DrawDrawing(draw.Drawing);
}
dc.Close();
return root;
}
#endregion
#region 属性
///
/// 画笔
///
public Pen Pen => new Pen(this.Brush, this.StrokeThickness);
///
/// 选择画笔
///
public Pen SelectPen { get; }
///
/// 选择底色画笔
///
public Pen SelectBackgroundPen { get; }
#endregion
#region 字段
///
/// 正在进行的画图工具
///
private List workingDrawTools = new List();
private Cursor originalCursor;
///
/// 原始指针
///
public Cursor OriginalCursor
{
get => originalCursor;
set
{
if (originalCursor == value)
return;
originalCursor = value;
if (!handleCursor)
this.Cursor = value;
}
}
///
/// 鼠标指针是否正在被控制
///
public Boolean handleCursor;
public Boolean squareCursor;
public UInt32 cursorLength;
public Double cursorZoom;
private Point? lastPoint;
private DrawingCanvasViewer drawViewer;
private Boolean canDragStart => this.Cursor == DrawCursors.Hand && drawViewer != null;
private Boolean canDragMove => canDragStart && lastPoint.HasValue;
#endregion
}
}