using DH.Commons.Enums;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

using static DH.Commons.Enums.EnumHelper;


namespace DH.UI.Model.Winform
{
    public partial class CanvasImage : UserControl
    {
        public CanvasImage()
        {
            InitializeComponent();

            DoubleBuffered = true;
            SetStyle(ControlStyles.OptimizedDoubleBuffer |
                            ControlStyles.ResizeRedraw |
                            ControlStyles.AllPaintingInWmPaint, true);

            MouseWheel += Canvas_MouseWheel;
            KeyDown += OnCanvasKeyDown;
            KeyPress += OnCanvasKeyPressed;
            MouseDoubleClick += Canvas_MouseDoubleClick;
            MouseDown += Canvas_MouseDown;
            MouseMove += Canvas_MouseMove;
            MouseUp += Canvas_MouseUp;

           // EventRouter.ChangeElementsMouseState -= OnElementChangeMouseState;
           // EventRouter.ChangeElementsMouseState += OnElementChangeMouseState;

            //Elements.CollectionChanged += Elements_CollectionChanged;
        }

        private void Elements_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //this.Invoke(new Action(() =>
            //{
            //    this.Invalidate();
            //}));
        }

        #region Event
        public Action<MouseState> OnMouseStateChanged;
        public Action<IShapeElement> DrawTemplateChanged = null;
        public Action<Point, PointF, string> OnMouseLocationUpdated;
        #endregion

        private MouseState mouseState = MouseState.Normal;
        public MouseState MouseState
        {
            get
            {
                return mouseState;
            }
            set
            {
                if (mouseState != value)
                {
                    mouseState = value;

                    // OnMouseStateChanged?.BeginInvoke(value, null, null);
                    Task.Run(() => OnMouseStateChanged.Invoke(value));
                }
            }
        }

        #region 属性和字段

        //private Bitmap map = new Bitmap(10, 10);
        //public Bitmap MAP
        //{
        //    get
        //    {
        //        _mapLoadHandler.WaitOne();
        //        return map;
        //    }
        //    set
        //    {
        //        map = value;
        //    }
        //}

        public Bitmap MAP { get; set; } = new Bitmap(10, 10);

        public Matrix Matrix { get; set; } = new Matrix();
        public ObservableCollection<IShapeElement> Elements { get; set; } = new ObservableCollection<IShapeElement>();

        RectangleF _selectionRect = new RectangleF();
        #endregion

        #region 重绘
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                //lock (_mapLoadLock)
                //{ }

                Rectangle rect = ClientRectangle;
                Graphics originG = e.Graphics;
                BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current;
                BufferedGraphics myBuffer = currentContext.Allocate(originG, rect);
                Graphics g = myBuffer.Graphics;
                g.SmoothingMode = SmoothingMode.HighSpeed;
                g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
                g.InterpolationMode = InterpolationMode.NearestNeighbor;
                g.Clear(BackColor);

                g.MultiplyTransform(Matrix);

                if (MAP != null)
                {
                    try
                    {
                        g.DrawImage(MAP, 0, 0, MAP.Width, MAP.Height);
                    }
                    catch (Exception ex)
                    {
                    }
                }
                else
                {
                    g.Clear(BackColor);
                }

                DrawTemplate?.Draw(g);
                foreach (IShapeElement ele in Elements)
                {
                    if (ele.IsEnabled && ele.IsShowing)
                    {
                        ele.Draw(g);
                    }
                }

                #region Grid
                if (MAP != null)
                {
                    if (ShowGrid)
                    {
                        int baseX = MAP.Width / 2;
                        int baseY = MAP.Height / 2;

                        Point[] xPoint = new Point[] { new Point(0, baseY), new Point(MAP.Width, baseY) };
                        Point[] yPoint = new Point[] { new Point(baseX, 0), new Point(baseX, MAP.Height) };

                        g.DrawLine(new Pen(Pen_Grid.Color, 5.0f), xPoint[0], xPoint[1]);
                        g.DrawLine(new Pen(Pen_Grid.Color, 5.0f), yPoint[0], yPoint[1]);

                        if (GridValue > 0)
                        {
                            int stepX = MAP.Width / 2 / (GridValue * MAP.Width / 2 / _minGridStep / 10);
                            int stepY = MAP.Height / 2 / (GridValue * MAP.Height / 2 / _minGridStep / 10);

                            //int stepX = _minGridStep + (10 - GridValue) * (MAP.Width / 2 - _minGridStep) / 10;
                            //int stepY = _minGridStep + (10 - GridValue) * (MAP.Height / 2 - _minGridStep) / 10;

                            int yPositive = baseY;
                            do
                            {
                                xPoint = new Point[] { new Point(0, yPositive), new Point(MAP.Width, yPositive) };
                                g.DrawLine(Pen_Grid, xPoint[0], xPoint[1]);
                                yPositive -= stepY;
                            } while (yPositive > 0);

                            int yNegative = baseY;
                            do
                            {
                                xPoint = new Point[] { new Point(0, yNegative), new Point(MAP.Width, yNegative) };
                                g.DrawLine(Pen_Grid, xPoint[0], xPoint[1]);
                                yNegative += stepY;
                            } while (yNegative < MAP.Height);

                            int xPositive = baseX;
                            do
                            {
                                yPoint = new Point[] { new Point(xPositive, 0), new Point(xPositive, MAP.Height) };
                                g.DrawLine(Pen_Grid, yPoint[0], yPoint[1]);
                                xPositive -= stepX;
                            } while (xPositive > 0);

                            int xNegative = baseX;
                            do
                            {
                                yPoint = new Point[] { new Point(xNegative, 0), new Point(xNegative, MAP.Height) };
                                g.DrawLine(Pen_Grid, yPoint[0], yPoint[1]);
                                xNegative += stepX;
                            } while (xNegative < MAP.Width);
                        }
                    }
                }
                #endregion

                if (MouseState == MouseState.SelectionZoneDoing)
                {
                    g.DrawRectangle(Pens.AliceBlue, _selectionRect.X, _selectionRect.Y, _selectionRect.Width, _selectionRect.Height);
                    g.FillRectangle(new SolidBrush(Color.FromArgb(40, 0, 0, 255)), _selectionRect);
                }

                myBuffer.Render(originG);
                g.Dispose();
                myBuffer.Dispose();//释放资源
            }
            catch (Exception)
            {
            }
        }

        private void halfTransparent()
        {
        }
        #endregion

        #region 绘制类型
        private IShapeElement drawTemplate = null;
        public IShapeElement DrawTemplate
        {
            get
            {
                return drawTemplate;
            }
            set
            {
                if (drawTemplate != value)
                {

                    drawTemplate = value;

                    //DrawTemplateChanged?.BeginInvoke(value, null, null);
                    Task.Run(() => DrawTemplateChanged.Invoke(value));

                    if (value == null)
                    {
                        MouseState = MouseState.Normal;
                        return;
                    }

                    MouseState = MouseState.New;

                    var existed = Elements.FirstOrDefault(e => e.ID == value.ID);
                    if (existed != null)
                    {
                        Elements.Remove(existed);
                    }

                    //if (DrawTemplate != null)
                    //{
                    //    DrawTemplate.OnDrawDone += OnElementDrawDone;
                    //}
                }
            }
        }

        string currentElementId = "";
        string CurrentElementId
        {
            get
            {
                return currentElementId;
            }
            set
            {
                if (currentElementId != value)
                {
                    currentElementId = value;
                }
            }
        }

        private void OnElementDrawDone(IShapeElement ele)
        {
            //int maxIndex = 1;
            //if (Elements.Count > 0)
            //{
            //    maxIndex = Elements.Max(u => u.Index) + 1;
            //}
            //ele.Index = maxIndex;
            //ele.Name = maxIndex.ToString();

            //#region 获取基元的设备属性,目前包括运动坐标和相机参数
            //SetElementDevicePara?.Invoke(ele);
            //#endregion

            //Elements.Add(ele);
            //DrawTemplate = DrawTemplate?.Clone() as IShapeElement;
        }
        #endregion

        #region 状态变换
        private void OnElementChangeMouseState(IShapeElement ele, ElementState preState, ElementState curState)
        {
            if (curState != ElementState.Normal)
            {
                switch (curState)
                {
                    case ElementState.New:
                        MouseState = MouseState.New;
                        break;
                    case ElementState.Selected:
                        CurrentElementId = ele.ID;
                        Cursor = Cursors.Default;
                        break;
                    case ElementState.Moving:
                        MouseState = MouseState.MoveElement;
                        Cursor = Cursors.NoMove2D;
                        break;
                    case ElementState.Editing:
                        MouseState = MouseState.Editing;
                        Cursor = Cursors.Hand;
                        break;
                    case ElementState.MouseInSide:
                        MouseState = MouseState.InSideElement;
                        break;
                    case ElementState.MouseHover:
                        MouseState = MouseState.HoverElement;
                        break;
                    case ElementState.CanStretchLeft:
                        Cursor = Cursors.SizeWE;
                        break;
                    case ElementState.StretchingLeft:
                        MouseState = MouseState.StretchingLeft;
                        Cursor = Cursors.SizeWE;
                        break;
                    case ElementState.CanStretchBottom:
                        Cursor = Cursors.SizeNS;
                        break;
                    case ElementState.StretchingBottom:
                        MouseState = MouseState.StretchingBottom;
                        Cursor = Cursors.SizeNS;
                        break;
                    case ElementState.CanStretchRight:
                        Cursor = Cursors.SizeWE;
                        break;
                    case ElementState.StretchingRight:
                        MouseState = MouseState.StretchingRight;
                        Cursor = Cursors.SizeWE;
                        break;
                    case ElementState.CanStretchTop:
                        Cursor = Cursors.SizeNS;
                        break;
                    case ElementState.StretchingTop:
                        MouseState = MouseState.StretchingTop;
                        Cursor = Cursors.SizeNS;
                        break;

                    case ElementState.CanStretchLeftLowerCorner:
                        Cursor = Cursors.SizeNESW;
                        break;
                    case ElementState.StretchingLeftLowerCorner:
                        MouseState = MouseState.StretchingLeftLowerCorner;
                        Cursor = Cursors.SizeNESW;
                        break;
                    case ElementState.CanStretchLeftUpperCorner:
                        Cursor = Cursors.SizeNWSE;
                        break;
                    case ElementState.StretchingLeftUpperCorner:
                        MouseState = MouseState.StretchingLeftUpperCorner;
                        Cursor = Cursors.SizeNWSE;
                        break;
                    case ElementState.CanStretchRightLowerCorner:
                        Cursor = Cursors.SizeNWSE;
                        break;
                    case ElementState.StretchingRightLowerCorner:
                        MouseState = MouseState.StretchingRightLowerCorner;
                        Cursor = Cursors.SizeNWSE;
                        break;
                    case ElementState.CanStretchRightUpperCorner:
                        Cursor = Cursors.SizeNESW;
                        break;
                    case ElementState.StretchingRightUpperCorner:
                        MouseState = MouseState.StretchingRightUpperCorner;
                        Cursor = Cursors.SizeNESW;
                        break;
                    default:
                        //MouseState = MouseState.Normal;
                        break;
                }
            }
            else
            {
                if (Elements.All(e => e.State == ElementState.Normal))
                {
                    CurrentElementId = null;

                    if (preState == ElementState.Selected)
                    {
                        DrawTemplate = null;
                    }
                    else if (DrawTemplate != null)
                    {
                        MouseState = MouseState.New;
                        return;
                    }

                    //MouseState = MouseState.Normal;
                }
            }

            this.Invalidate();
        }
        #endregion

        #region 鼠标动作
        private void Canvas_MouseWheel(object sender, MouseEventArgs e)
        {
            PointF prePoint = ToMapPoint(e.Location);

            //先缩放
            if (e.Delta > 0)
            {
                Matrix.Scale((float)1.1, (float)1.1);
            }
            else
            {
                Matrix.Scale((float)0.9, (float)0.9);
            }

            PointF afterPoint = ToMapPoint(e.Location);

            //后平移
            Matrix.Translate(afterPoint.X - prePoint.X, afterPoint.Y - prePoint.Y);

            Invalidate();
        }

        PointF startPoint, currentPoint;
        bool _isMouseBtnPressing = false;

        private void Canvas_MouseDown(object sender, MouseEventArgs e)
        {
            PointF p = ToMapPoint(e.Location);

            if (e.Button == MouseButtons.Left)
            {
                _isMouseBtnPressing = true;

                switch (MouseState)
                {
                    case MouseState.Normal:
                        startPoint = e.Location;
                        break;
                    case MouseState.StretchingLeft:
                        break;
                    case MouseState.StretchingRight:
                        break;
                    case MouseState.StretchingTop:
                        break;
                    case MouseState.StretchingBottom:
                        break;
                    case MouseState.MoveElement:
                        break;
                    case MouseState.HoverElement:
                    case MouseState.InSideElement:
                    case MouseState.New:
                        DrawTemplate?.OnMouseDown(p);
                        break;
                    case MouseState.Editing:
                        break;
                    case MouseState.SelectionZone:
                        MouseState = MouseState.SelectionZoneDoing;
                        startPoint = p;
                        break;
                }

                foreach (IShapeElement ele in Elements)
                {
                    ele.OnMouseDown(p);
                }
            }
            else if (e.Button == MouseButtons.Right)
            {
                if (DrawTemplate != null && DrawTemplate.State == ElementState.New && DrawTemplate.IsCreatedDone())
                {
                    IShapeElement ele = DrawTemplate.Clone() as IShapeElement;
                    ele.State = ElementState.Normal;
                    Elements.Add(ele);

                   // (DrawTemplate as ElementBase).Initial();
                }
            }
        }

        private void Canvas_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
                return;

            _isMouseBtnPressing = false;
            switch (MouseState)
            {
                case MouseState.Normal:
                    break;
                case MouseState.HoverElement:
                    break;
                case MouseState.InSideElement:
                    break;
                case MouseState.StretchingLeft:
                    break;
                case MouseState.StretchingRight:
                    break;
                case MouseState.StretchingTop:
                    break;
                case MouseState.StretchingBottom:
                    break;
                case MouseState.MoveElement:
                    //MouseState = MouseState.SelectedElement;
                    break;
                case MouseState.New:
                    break;
                case MouseState.Editing:
                    break;
                case MouseState.MovingAll:
                    MouseState = MouseState.Normal;
                    break;
                case MouseState.SelectionZone:
                    break;
                case MouseState.SelectionZoneDoing:
                    MouseState = MouseState.SelectionZone;

                    foreach (IShapeElement ele in Elements)
                    {
                        ele.State = ElementState.Normal;
                        if (ele.IsIntersect(_selectionRect))
                        {
                            ele.State = ElementState.Selected;
                        }
                    }

                    break;
            }

            Cursor = Cursors.Default;

            if (MouseState != MouseState.SelectionZone)
            {
                PointF p = ToMapPoint(e.Location);
                DrawTemplate?.OnMouseUp(p);
                foreach (IShapeElement ele in Elements)
                {
                    ele.OnMouseUp(p);
                }
            }
        }

        private void Canvas_MouseMove(object sender, MouseEventArgs e)
        {
            PointF p = ToMapPoint(e.Location);

            switch (MouseState)
            {
                case MouseState.Normal:
                    {
                        if (_isMouseBtnPressing)
                        {
                            currentPoint = e.Location;
                            PointF p1 = ToMapPoint(startPoint);
                            PointF p2 = ToMapPoint(currentPoint);
                            Matrix.Translate(p2.X - p1.X, p2.Y - p1.Y);
                            startPoint = e.Location;
                        }
                    }
                    break;
                case MouseState.StretchingLeft:
                    break;
                case MouseState.StretchingRight:
                    break;
                case MouseState.StretchingTop:
                    break;
                case MouseState.StretchingBottom:
                    break;
                case MouseState.MoveElement:
                    break;
                case MouseState.HoverElement:
                case MouseState.InSideElement:
                case MouseState.New:
                    DrawTemplate?.OnMouseMove(p);
                    break;
                case MouseState.Editing:
                    break;
                case MouseState.MovingAll:
                    break;
                case MouseState.SelectionZoneDoing:
                    {
                        currentPoint = p;

                        float[] x2 = new float[2] { startPoint.X, currentPoint.X };
                        float[] y2 = new float[2] { startPoint.Y, currentPoint.Y };

                        float xMin = x2.Min();
                        float xMax = x2.Max();
                        float yMin = y2.Min();
                        float yMax = y2.Max();

                        _selectionRect = new RectangleF(xMin, yMin, xMax - xMin, yMax - yMin);
                    }
                    break;
            }

            PointF mapPoint = ToMapPoint(e.Location);
            Color color = Color.Transparent;
            if (MAP != null && mapPoint.X > 0 && mapPoint.X < MAP.Width && mapPoint.Y > 0 && mapPoint.Y < MAP.Height)
            {
                color = MAP.GetPixel((int)mapPoint.X, (int)mapPoint.Y);
            }

            // OnMouseLocationUpdated?.BeginInvoke(e.Location, mapPoint, color.Name, null, null); 
            Task.Run(() => OnMouseLocationUpdated?.Invoke(e.Location, mapPoint, color.Name));

            if (MouseState != MouseState.SelectionZoneDoing)
            {
                Elements.ToList().ForEach(ele => ele?.OnMouseMove(p));
            }

            Invalidate();
        }

        private void Canvas_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            PointF p = ToMapPoint(e.Location);

            if (e.Button == MouseButtons.Left)
            {
                switch (MouseState)
                {
                    //case MouseState.SelectedElement:
                    case MouseState.HoverElement:
                    case MouseState.InSideElement:
                    case MouseState.MoveElement:
                    case MouseState.Normal:
                        //Elements.ForEach(ele =>
                        foreach (IShapeElement ele in Elements)
                        {
                            ele.OnMouseDoubleClick(p);
                        }
                        //);
                        break;
                    default:
                        break;
                }
            }
            else
            {
                //if (MouseState == MouseState.SelectedElement)
                {
                    MouseState = MouseState.Normal;

                    //Elements.ForEach(ele =>
                    foreach (IShapeElement ele in Elements)
                    {
                        ele.State = ElementState.Normal;
                    }
                    //);
                }
            }
        }
        #endregion

        #region 图片操作
        bool _firstLoad = true;
        object _mapLoadLock = new object();
        ManualResetEvent _mapLoadHandler = new ManualResetEvent(true);
        ManualResetEvent _mapUsingHandler = new ManualResetEvent(false);

        /// <summary>
        /// 载入图片
        /// </summary>
        /// <param name="bitmap"></param>
        public void LoadImage(Bitmap bitmap)
        {
            if (bitmap == null)
                return;

            ////lock (_mapLoadLock)
            ////_mapUsingHandler.WaitOne();
            //_mapLoadHandler.Reset();
            //{
            //    map?.Dispose();
            //    map = null;
            //    map = bitmap;
            //}
            //_mapLoadHandler.Set();

            MAP = bitmap;

            if (_firstLoad)
            {
                SetScreenSize();
                _firstLoad = false;
            }
            Invalidate();
        }

        public void Clear()
        {
            MAP = null;
            Elements.Clear();

            Invalidate();
        }

        /// <summary>
        /// 设置图片为原始尺寸
        /// </summary>
        public void SetMapSize()
        {
            Matrix = new Matrix();
            Invalidate();
        }

        /// <summary>
        /// 设置图片为适配尺寸
        /// </summary>
        public void SetScreenSize()
        {
            try
            {
                if (MAP == null)
                    return;

                Matrix = new Matrix();

                //先缩放
                List<float> ratios = new List<float>() { MAP.Width / (float)Width, MAP.Height / (float)Height };
                float ratio = 1 / ratios.Max();
                Matrix.Scale(ratio, ratio);

                //再平移
                //将plMain的中心转换为图片坐标
                PointF screenCenter = new PointF(Width / 2.0f, Height / 2.0f);
                PointF mapPoint = ToMapPoint(screenCenter);

                //目标坐标减去当前坐标
                Matrix.Translate(-MAP.Width / 2.0f + mapPoint.X, -MAP.Height / 2.0f + mapPoint.Y);

                Invalidate();
            }
            catch (Exception ex)
            {
                //Trace.TraceError(ex.GetExceptionMessage());
            }
        }
        #endregion

        #region 私有方法
        //private void DisplayMouseLocation(Point location)
        //{
        //    string screenPoint = string.Format("屏幕坐标X:{0};Y:{1}", location.X, location.Y);

        //    Point mapPoint = ToMapPoint(location);
        //    string mapPointStr = string.Format("图片坐标X:{0};Y:{1}", mapPoint.X, mapPoint.Y);

        //    tsslLocation.Text = screenPoint + "       " + mapPointStr;
        //}

        private PointF ToMapPoint(PointF p)
        {
            PointF[] ps = new PointF[] { p };
            Matrix invertMatrix = Matrix.Clone();
            invertMatrix.Invert();
            invertMatrix.TransformPoints(ps);

            return ps[0];
        }

        private Point ToScreenPoint(Point p)
        {
            Point[] ps = new Point[] { p };
            Matrix.TransformPoints(ps);

            return ps[0];
        }

        #endregion

        #region 按键操作
        public void OnCanvasKeyPressed(object sender, KeyPressEventArgs e)
        {
            //if (e.KeyChar == 27)  //Esc
            //{
            //    //if (MouseState == MouseState.SelectedElement)
            //    {
            //        MouseState = MouseState.Normal;

            //        //Elements.ForEach(ele =>
            //        foreach (IShapeElement ele in Elements)
            //        {
            //            ele.State = ElementState.Normal;
            //        }
            //        //);
            //    }
            //}

            //Invalidate();
        }

        public void OnCanvasKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete) //delete键
            {
                Elements.Remove(Elements.FirstOrDefault(u => u.ID == CurrentElementId));
            }

            if (e.KeyData == Keys.Escape)  //Esc
            {
                if (DrawTemplate != null /*&& (DrawTemplate as ElementBase).CreatePoints.Count > 0*/)
                {
                    DrawTemplate.Initial();
                }
                else
                {
                    DrawTemplate = null;

                    if (MouseState != MouseState.Normal)
                    {
                        MouseState = MouseState.Normal;
                    }
                    else
                    {
                        Elements.ToList().ForEach(u => u.State = ElementState.Normal);
                    }
                }
            }

            //if (e.KeyData == Keys.Up)
            //{
            //    Elements.ToList().ForEach(u =>
            //    {
            //        if (u.State == ElementState.Selected)
            //        {
            //            u.Translate(0, -1);
            //        }
            //    });
            //}

            //if (e.KeyData == Keys.Down)
            //{
            //    Elements.ToList().ForEach(u =>
            //    {
            //        if (u.State == ElementState.Selected)
            //        {
            //            u.Translate(0, 1);
            //        }
            //    });
            //}

            //if (e.KeyData == Keys.Left)
            //{
            //    Elements.ToList().ForEach(u =>
            //    {
            //        if (u.State == ElementState.Selected)
            //        {
            //            u.Translate(-1, 0);
            //        }
            //    });
            //}

            //if (e.KeyData == Keys.Right)
            //{
            //    Elements.ToList().ForEach(u =>
            //    {
            //        if (u.State == ElementState.Selected)
            //        {
            //            u.Translate(1, 0);
            //        }
            //    });
            //}

            Invalidate();
        }
        #endregion

        #region 基元的设备属性 运动设置和相机设置
        public Action<IShapeElement> SetElementDevicePara;

        public Action<IShapeElement> SetDeviceByElement;
        #endregion

        #region Grid
        private bool showGrid = false;
        public bool ShowGrid
        {
            get => showGrid;
            set
            {
                showGrid = value;
                Invalidate();
            }
        }

        private int gridValue = 0;
        public int GridValue
        {
            get => gridValue;
            set
            {
                gridValue = value;
                Invalidate();
            }
        }

        private Pen penGrid = new Pen(Color.FromArgb(120, Color.Red), 1.0f);
        public Pen Pen_Grid
        {
            get => penGrid;
            set
            {
                penGrid = value;
                Invalidate();
            }
        }

        readonly int _minGridStep = 10;
        #endregion

        #region Dispose
        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            MAP?.Dispose();
            Matrix?.Dispose();
            penGrid?.Dispose();

            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #endregion
    }
}