领胜LDS 键盘AOI检测项目
wells.liu
2020-07-09 dac3e12cc046aabeefd828b3f03794fe2bc0ba06
Merge branch 'master' of http://gitblit.broconcentric.com:8088/r/M071
1个文件已添加
26个文件已修改
1255 ■■■■ 已修改文件
.gitignore 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Device/DeviceBase/CameraBase.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Device/Helper/AspectHelper.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Common.Model/Helper/EnumHelper.cs 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.Gocator/Bro.Device.Gocator.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Device.Gocator/GocatorDriver.cs 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/Bro.M071.Process.csproj 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Models.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process.cs 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/M071Process_MotionCard.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/KeyIndicator.cs 72 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_MainForm.Designer.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_MainForm.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_ShortcutFrm.Designer.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_ShortcutFrm.cs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.M071.Process/UI/M071_ShortcutFrm.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.Process/Bro.Process.csproj 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Config/AdvancedPwdFrm.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Config/AdvancedPwdFrm.designer.cs 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Config/MainFrm.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Device.Winform/CtrlCameraRunBase.Designer.cs 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Device.Winform/CtrlCameraRunBase.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Device.Winform/CtrlCameraRunBase.resx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/ElementBase.cs 312 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/Canvas.cs 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/CanvasImage.cs 211 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/Bro.UI.Model.Winform/UI/DockContent/MenuFrmBase.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.gitignore
@@ -188,3 +188,5 @@
# Microsoft Fakes
FakesAssemblies/
/src/Images/20200706/Test/Origin
/src/Images
src/Bro.Common.Device/DeviceBase/CameraBase.cs
@@ -152,7 +152,7 @@
            set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
            set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
            set.IsAddtionalSaved = !string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
            set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
            set.OnImageSetTimeout += ImageSet_OnImageSetTimeout;
            _imageSetList.Add(set);
@@ -181,7 +181,7 @@
        {
            set.IsOriginSaved = !set.ImageSaveOption.IsSaveOriginImage;
            set.IsFitSaved = !set.ImageSaveOption.IsSaveFitImage;
            set.IsAddtionalSaved = !string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
            set.IsAddtionalSaved = string.IsNullOrWhiteSpace(set.ImageSaveOption.AddtionalSaveType);
            set.OnImageSetTimeout += ImageSet_OnImageSetTimeout;
            _imageSetList.Add(set);
        }
@@ -539,7 +539,7 @@
            });
        }
        protected async void Generate16GrayImageByPointer(int width, int height, IntPtr dataPtr, string imgSetId)
        protected async Task Generate16GrayImageByPointer(int width, int height, IntPtr dataPtr, string imgSetId)
        {
            await Task.Run(() =>
            {
@@ -897,7 +897,7 @@
        public ImageSet()
        {
            autoDisposeTimer = new Timer(OnAutoDispose, null, -1, 10 * 1000);
            autoDisposeTimer = new Timer(OnAutoDispose, null, 10 * 1000, -1);
        }
        public virtual void Dispose()
src/Bro.Common.Device/Helper/AspectHelper.cs
@@ -88,7 +88,7 @@
            //    new ProcessException(ex);
            //}
            args.FlowBehavior = FlowBehavior.Return;
            args.FlowBehavior = FlowBehavior.ThrowException;
        }
    }
    #endregion
src/Bro.Common.Model/Helper/EnumHelper.cs
@@ -392,6 +392,26 @@
            Measuring = 21,
            MeasureDoneOK = 22,
            MeasureDoneNG = 23,
            CanStretchLeft = 41,
            CanStretchRight = 42,
            CanStretchTop = 43,
            CanStretchBottom = 44,
            CanStretchLeftUpperCorner = 45,
            CanStretchLeftLowerCorner = 46,
            CanStretchRightUpperCorner = 47,
            CanStretchRightLowerCorner = 48,
            StretchingLeft = 31,
            StretchingRight = 32,
            StretchingTop = 33,
            StretchingBottom = 34,
            StretchingLeftUpperCorner = 35,
            StretchingLeftLowerCorner = 36,
            StretchingRightUpperCorner = 37,
            StretchingRightLowerCorner = 38,
        }
        public enum MouseState
@@ -400,15 +420,21 @@
            HoverElement = 2,
            InSideElement = 3,
            MoveElement = 4,
            StretchingLeft = 11,
            StretchingRight = 12,
            StretchingUp = 13,
            StretchingDown = 14,
            MoveElement = 15,
            StretchingTop = 13,
            StretchingBottom = 14,
            StretchingLeftUpperCorner = 15,
            StretchingLeftLowerCorner = 16,
            StretchingRightUpperCorner =17,
            StretchingRightLowerCorner = 18,
            New = 21,
            Editing = 22,
            SelectedElement = 23,
            //SelectedElement = 23,
            MovingAll = 31,
src/Bro.Device.Gocator/Bro.Device.Gocator.csproj
@@ -22,6 +22,7 @@
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
    <PlatformTarget>x64</PlatformTarget>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
src/Bro.Device.Gocator/GocatorDriver.cs
@@ -86,18 +86,88 @@
                            long bufferSize = width * height;
                            IntPtr bufferPointer = surfaceMsg.Data;
                            float zoomFactor = (float)((double)surfaceMsg.YResolution / (double)surfaceMsg.XResolution);
                            int zoomHeight = (int)(zoomFactor * height);
                            IntPtr zoomPtr = Marshal.AllocHGlobal(zoomHeight * (int)width * 2);
                            //没有插值,默认0
                            //Parallel.For(0, height, h =>
                            //  {
                            //      CopyMemory((IntPtr)((long)zoomPtr + width * 2 * Math.Floor(h * zoomFactor)), (IntPtr)((long)bufferPointer + width * 2 * h), width * 2);
                            //  });
                            //使用上一行原有数据
                            Parallel.For(0, zoomHeight, h =>
                            {
                                int originHeightIndex = (int)Math.Floor((double)height * h / (double)zoomHeight);
                                CopyMemory((IntPtr)((long)zoomPtr + width * 2 * h), (IntPtr)((long)bufferPointer + width * 2 * originHeightIndex), width * 2);
                            });
                            if (imgSet != null)
                            {
                                imgSet.HImage = new HImage();
                                imgSet.HImage.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                                imgSet.HImage.GenImage1("uint2", (int)width, zoomHeight, zoomPtr);
                                //imgSet.HImage = imgSet.HImage.ZoomImageSize((int)width, zoomHeight, "constant");
                                imgSet.HImage_2 = new HImage();
                                imgSet.HImage_2.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                                imgSet.HImage_2.GenImage1("uint2", (int)width, zoomHeight, zoomPtr);
                                //imgSet.HImage_2 = imgSet.HImage_2.ZoomImageSize((int)width, zoomHeight, "constant");
                            }
                            Generate16GrayImageByPointer((int)width, (int)height, bufferPointer, imgSet?.Id);
                            Generate16GrayImageByPointer((int)width, zoomHeight, zoomPtr, imgSet?.Id).ContinueWith(t =>
                            {
                                Marshal.FreeHGlobal(zoomPtr);
                            });
                            //int zoomHeight = (int)(((double)surfaceMsg.YResolution / (double)surfaceMsg.XResolution) * (double)surfaceMsg.Length);
                            //if (imgSet != null)
                            //{
                            //    imgSet.HImage = new HImage();
                            //    imgSet.HImage.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                            //    imgSet.HImage = imgSet.HImage.ZoomImageSize((int)width, zoomHeight, "constant");
                            //    imgSet.HImage_2 = new HImage();
                            //    imgSet.HImage_2.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                            //    imgSet.HImage_2 = imgSet.HImage_2.ZoomImageSize((int)width, zoomHeight, "constant");
                            //}
                            //Generate16GrayImageByPointer((int)width, (int)height, bufferPointer, imgSet?.Id);
                        }
                        break;
                        //case GoDataMessageType.SurfaceIntensity:
                        //    {
                        //        GoSurfaceIntensityMsg surfaceMsg = (GoSurfaceIntensityMsg)dataObj;
                        //        long width = surfaceMsg.Width;
                        //        long height = surfaceMsg.Length;
                        //        long bufferSize = width * height;
                        //        IntPtr bufferPointer = surfaceMsg.Data;
                        //        //int zoomHeight = (surfaceMsg.YResolution * (int)surfaceMsg.Length * 10) / surfaceMsg.XResolution;
                        //        int zoomHeight = (int)(((double)surfaceMsg.YResolution / (double)surfaceMsg.XResolution) * (double)surfaceMsg.Length);
                        //        if (imgSet != null)
                        //        {
                        //            imgSet.HImage = new HImage();
                        //            imgSet.HImage.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                        //            imgSet.HImage = imgSet.HImage.ZoomImageSize((int)width, zoomHeight, "constant");
                        //            imgSet.HImage_2 = new HImage();
                        //            imgSet.HImage_2.GenImage1("uint2", (int)width, (int)height, bufferPointer);
                        //            imgSet.HImage_2 = imgSet.HImage_2.ZoomImageSize((int)width, zoomHeight, "constant");
                        //        }
                        //        Generate16GrayImageByPointer((int)width, (int)height, bufferPointer, imgSet?.Id);
                        //    }
                        //    break;
                }
            }
        }
@@ -336,9 +406,9 @@
        public override async void SaveOriginImage(Bitmap map, Bitmap showImage, string imgSetId)
        {
            Task.Run(() =>
            {
                OnImageUpdated?.Invoke(this, showImage, imgSetId);
            });
             {
                 OnImageUpdated?.Invoke(this, showImage, imgSetId);
             });
            GoImageSet set = _imageSetList.FirstOrDefault(u => u.Id == imgSetId) as GoImageSet;
src/Bro.M071.Process/Bro.M071.Process.csproj
@@ -152,6 +152,9 @@
    <EmbeddedResource Include="UI\M071_MainForm.resx">
      <DependentUpon>M071_MainForm.cs</DependentUpon>
    </EmbeddedResource>
    <EmbeddedResource Include="UI\M071_ShortcutFrm.resx">
      <DependentUpon>M071_ShortcutFrm.cs</DependentUpon>
    </EmbeddedResource>
    <None Include="App.config">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
src/Bro.M071.Process/M071Models.cs
@@ -137,13 +137,13 @@
            get => key;
            set
            {
                AlignName = key = value;
                AliasName = key = value;
            }
        }
        [Category("键名配置")]
        [Description("别名")]
        public string AlignName { get; set; }
        public string AliasName { get; set; }
        [Category("启用设置")]
        [Description("true:启用 false:禁用")]
@@ -178,7 +178,7 @@
        public string GetDisplayText()
        {
            return $"{AlignName}";
            return $"{AliasName}";
        }
        public List<string> GetHalconToolPathList()
src/Bro.M071.Process/M071Process.cs
@@ -58,8 +58,8 @@
        private void InitialSetting()
        {
            //数据库迁移检查
            DatabaseInitialize.Initialize();
            ////数据库迁移检查
            //DatabaseInitialize.Initialize();
            MotionCardSettingCheck();
@@ -78,21 +78,21 @@
                var snapshotPoint = Config.SnapshotPointCollection.FirstOrDefault(s => s.Id == u.SnapshotPointId && s.IsEnabled);
                if (snapshotPoint == null)
                    throw new ProcessException($"{u.AlignName}未设置可用拍照点位");
                    throw new ProcessException($"{u.AliasName}未设置可用拍照点位");
                if (u.ImageSeq < 1)
                    throw new ProcessException($"{u.AlignName}图片序号小于1");
                    throw new ProcessException($"{u.AliasName}图片序号小于1");
                var algo = Config.KeyAlgorithemCollection.FirstOrDefault(a => a.Id == u.KeyAlgorithemId);
                if (algo == null)
                    throw new ProcessException($"{u.AlignName}未设置检测算法");
                    throw new ProcessException($"{u.AliasName}未设置检测算法");
                u.KeyAlgorithemPath = algo.AlgorithemPath;
                LoadHalconTool(u.KeyAlgorithemPath, u.AlignName);
                LoadHalconTool(u.KeyAlgorithemPath, u.AliasName);
                var resultSet = Config.KeyResultCollection.FirstOrDefault(r => r.Id == u.KeyResultId);
                if (resultSet == null)
                    throw new ProcessException($"{u.AlignName}未设置检测结果配置");
                    throw new ProcessException($"{u.AliasName}未设置检测结果配置");
                u.KeyResultList = new List<string>(resultSet.Results);
            });
@@ -511,7 +511,7 @@
                 var excludeKeys = keys.Where(u => u.ImageSeq > count).ToList();
                 if (excludeKeys.Count > 0)
                 {
                     LogAsync(DateTime.Now, $"{string.Join(" ", excludeKeys.Select(u => u.AlignName))}未在图片获取序列中", "");
                     LogAsync(DateTime.Now, $"{string.Join(" ", excludeKeys.Select(u => u.AliasName))}未在图片获取序列中", "");
                     keyBindCollection.Where(k => excludeKeys.Any(u => u.Key == k.Key)).ToList().ForEach(k =>
                          {
                              k.FillKeyValues(null);
@@ -528,24 +528,24 @@
                             var keyBindList = keyBindCollection.Where(u => u.Key == k.Key).ToList();
                             string keyToolKey = k.AlignName + "|" + k.KeyAlgorithemPath;
                             string keyToolKey = k.AliasName + "|" + k.KeyAlgorithemPath;
                             if (!_halconToolDict.ContainsKey(keyToolKey))
                             {
                                 LogAsync(DateTime.Now, $"{k.AlignName}检测算法未初始化", "");
                                 LogAsync(DateTime.Now, $"{k.AliasName}检测算法未初始化", "");
                             }
                             else
                             {
                                 _halconToolDict[keyToolKey].InputImageDic["INPUT_Image"] = image;
                                 if (!_halconToolDict[keyToolKey].RunProcedure(out string error))
                                 {
                                     LogAsync(DateTime.Now, $"{k.AlignName}检测算法异常,{error}", "");
                                     LogAsync(DateTime.Now, $"{k.AliasName}检测算法异常,{error}", "");
                                 }
                                 else
                                 {
                                     var results = _halconToolDict[keyToolKey].GetResultTuple("OUTPUT_Results").HTupleToDouble();
                                     if (results.Count == 0 || results.Any(u => u < 0))
                                     {
                                         LogAsync(DateTime.Now, $"{k.AlignName}检测结果异常", "");
                                         LogAsync(DateTime.Now, $"{k.AliasName}检测结果异常", "");
                                     }
                                     else
                                     {
src/Bro.M071.Process/M071Process_MotionCard.cs
@@ -125,7 +125,7 @@
        private void MotionCardSettingCheck()
        {
            IDevice device = DeviceCollection.FirstOrDefault(u => u is IMotionCard);
            if (device.InitialConfig is MotionCardInitialConfigBase iConfig)
            if (device?.InitialConfig is MotionCardInitialConfigBase iConfig)
            {
                outputCtrlCard = device as MotionCardBase;
src/Bro.M071.Process/UI/KeyIndicator.cs
@@ -30,20 +30,6 @@
        [Browsable(false)]
        public override bool IsEnabled { get => base.IsEnabled; set => base.IsEnabled = value; }
        //[Category("显示设置")]
        //[Description("左上/开始点位")]
        //[TypeConverter(typeof(ComplexObjectConvert))]
        //[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
        //[Browsable(false)]
        //public CustomizedPoint StartPoint { get; set; } = new CustomizedPoint();
        //[Category("显示设置")]
        //[Description("显示区域大小")]
        //[TypeConverter(typeof(ComplexObjectConvert))]
        //[Editor(typeof(PropertyObjectEditor), typeof(UITypeEditor))]
        //public CustomizedPoint Size { get; set; } = new CustomizedPoint();
        [Category("显示设置")]
        [Description("标签显示区域")]
        [DisplayName("标签显示区域")]
@@ -68,6 +54,11 @@
            {
                DisplayRect = this.DisplayRect,
            };
        }
        protected override void SetSelectedPen()
        {
            Pen = new Pen(Color.Red, 6);
        }
        public override void Draw(Graphics g)
@@ -108,7 +99,12 @@
        public override bool IsMouseInSide(Point p)
        {
            return false;
            return p.X >= DisplayRect.X && p.X <= DisplayRect.X + DisplayRect.Width && p.Y >= DisplayRect.Y && p.Y <= DisplayRect.Y + DisplayRect.Height;
        }
        public override bool IsMouseCanMoveElement(Point p)
        {
            return IsMouseInSide(p);
        }
        public override void OnKeyDown(object sender, KeyEventArgs e)
@@ -133,6 +129,52 @@
        public override void Translate(int x, int y)
        {
            DisplayRect = new Rectangle(DisplayRect.X + x, DisplayRect.Y + y, DisplayRect.Width, DisplayRect.Height);
        }
        public override void Relocate(Point point)
        {
            DisplayRect = new Rectangle(point.X - DisplayRect.Width / 2, point.Y - DisplayRect.Height / 2, DisplayRect.Width, DisplayRect.Height);
        }
        public override bool IsMouseCanStretchBottom(Point p)
        {
            return Math.Abs(p.X - (DisplayRect.X + DisplayRect.Width / 2)) < 10 && Math.Abs(p.Y - DisplayRect.Y - DisplayRect.Height) < 10;
        }
        public override bool IsMouseCanStretchRight(Point p)
        {
            return Math.Abs(p.X - (DisplayRect.X + DisplayRect.Width)) < 10 && Math.Abs(p.Y - (DisplayRect.Y + DisplayRect.Height / 2)) < 10;
        }
        public override bool IsMouseCanStretchRightLowerCorner(Point p)
        {
            return Math.Abs(p.X - (DisplayRect.X + DisplayRect.Width)) < 10 && Math.Abs(p.Y - (DisplayRect.Y + DisplayRect.Height)) < 10;
        }
        int x, y = 0;
        public override void StretchBottom(Point p)
        {
            if (p.Y > DisplayRect.Y)
            {
                DisplayRect = new Rectangle(DisplayRect.X, DisplayRect.Y, DisplayRect.Width, p.Y - DisplayRect.Y);
            }
        }
        public override void StretchRight(Point p)
        {
            if (p.X > DisplayRect.X)
            {
                DisplayRect = new Rectangle(DisplayRect.X, DisplayRect.Y, p.X - DisplayRect.X, DisplayRect.Height);
            }
        }
        public override void StretchRightLowerCorner(Point p)
        {
            if (p.X > DisplayRect.X && p.Y > DisplayRect.Y)
            {
                DisplayRect = new Rectangle(DisplayRect.X, DisplayRect.Y, p.X - DisplayRect.X, p.Y - DisplayRect.Y);
            }
        }
        protected override void DrawResult(Graphics g)
src/Bro.M071.Process/UI/M071_MainForm.Designer.cs
@@ -240,6 +240,7 @@
            this.lvMeasures.UseCompatibleStateImageBehavior = false;
            this.lvMeasures.View = System.Windows.Forms.View.List;
            this.lvMeasures.SelectedIndexChanged += new System.EventHandler(this.lvMeasures_SelectedIndexChanged);
            this.lvMeasures.DoubleClick += new System.EventHandler(this.lvMeasures_DoubleClick);
            // 
            // propGridKeyIndicator
            // 
src/Bro.M071.Process/UI/M071_MainForm.cs
@@ -32,6 +32,13 @@
            plImage.Controls.Add(cvImage);
            tscEditLocation.Visible = tsmiShowEditor.Checked = false;
            this.Load += async (s, e) =>
               {
                   await Task.Delay(300);
                   cvImage.SetScreenSize();
               };
        }
        public override void OnProcessUpdated()
@@ -48,6 +55,7 @@
            {
                Bitmap image = (Bitmap)Image.FromFile(Config.BackgroundImagePath);
                cvImage.LoadImage(image);
                cvImage.SetScreenSize();
            }
            catch (Exception ex)
            {
@@ -70,7 +78,8 @@
                lvMeasures.Items.Add(item);
            });
            txtBarcode.ReadOnly = Config.IsBarcodeManulInputBlocked;
            if (txtBarcode.IsHandleCreated)
                txtBarcode.BeginInvoke(new Action(() => txtBarcode.ReadOnly = Config.IsBarcodeManulInputBlocked));
            Process_M071.OnClearBarcode -= M071_MainForm_OnClearBarcode;
            Process_M071.OnClearBarcode += M071_MainForm_OnClearBarcode;
@@ -150,6 +159,19 @@
            MessageBox.Show("标签修改完成");
        }
        private void lvMeasures_DoubleClick(object sender, EventArgs e)
        {
            if (lvMeasures.SelectedItems.Count <= 0)
                return;
            var ele = cvImage.Elements.FirstOrDefault(u => u.ID == lvMeasures.SelectedItems[0].Tag.ToString());
            if (ele != null)
            {
                ele.State = ElementState.Selected;
                cvImage.Invalidate();
            }
        }
        #endregion
        #region 上方状态区
@@ -169,6 +191,11 @@
                txtBarcode.Text = _barcode;
                _barcode = "";
            }
            if (e.KeyValue == 27)
            {
                cvImage.Elements.ToList().ForEach(ele => ele.State = ElementState.Normal);
            }
        }
        private void txtBarcode_TextChanged(object sender, EventArgs e)
src/Bro.M071.Process/UI/M071_ShortcutFrm.Designer.cs
@@ -28,12 +28,103 @@
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
            this.chkBlockSaftyDoor = new System.Windows.Forms.CheckBox();
            this.chkBlockSafetyBeam = new System.Windows.Forms.CheckBox();
            this.chkBlockBeep = new System.Windows.Forms.CheckBox();
            this.chkManualInputForbidden = new System.Windows.Forms.CheckBox();
            this.btnLightSwitch = new System.Windows.Forms.Button();
            this.flowLayoutPanel1.SuspendLayout();
            this.SuspendLayout();
            //
            // flowLayoutPanel1
            //
            this.flowLayoutPanel1.Controls.Add(this.chkBlockSaftyDoor);
            this.flowLayoutPanel1.Controls.Add(this.chkBlockSafetyBeam);
            this.flowLayoutPanel1.Controls.Add(this.chkBlockBeep);
            this.flowLayoutPanel1.Controls.Add(this.chkManualInputForbidden);
            this.flowLayoutPanel1.Controls.Add(this.btnLightSwitch);
            this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
            this.flowLayoutPanel1.Name = "flowLayoutPanel1";
            this.flowLayoutPanel1.Size = new System.Drawing.Size(800, 450);
            this.flowLayoutPanel1.TabIndex = 0;
            //
            // chkBlockSaftyDoor
            //
            this.chkBlockSaftyDoor.AutoSize = true;
            this.chkBlockSaftyDoor.Location = new System.Drawing.Point(3, 3);
            this.chkBlockSaftyDoor.Name = "chkBlockSaftyDoor";
            this.chkBlockSaftyDoor.Size = new System.Drawing.Size(86, 17);
            this.chkBlockSaftyDoor.TabIndex = 0;
            this.chkBlockSaftyDoor.Text = "屏蔽安全门";
            this.chkBlockSaftyDoor.UseVisualStyleBackColor = true;
            this.chkBlockSaftyDoor.CheckedChanged += new System.EventHandler(this.chkBlockSaftyDoor_CheckedChanged);
            //
            // chkBlockSafetyBeam
            //
            this.chkBlockSafetyBeam.AutoSize = true;
            this.chkBlockSafetyBeam.Location = new System.Drawing.Point(95, 3);
            this.chkBlockSafetyBeam.Name = "chkBlockSafetyBeam";
            this.chkBlockSafetyBeam.Size = new System.Drawing.Size(98, 17);
            this.chkBlockSafetyBeam.TabIndex = 1;
            this.chkBlockSafetyBeam.Text = "屏蔽安全光线";
            this.chkBlockSafetyBeam.UseVisualStyleBackColor = true;
            this.chkBlockSafetyBeam.CheckedChanged += new System.EventHandler(this.chkBlockSafetyBeam_CheckedChanged);
            //
            // chkBlockBeep
            //
            this.chkBlockBeep.AutoSize = true;
            this.chkBlockBeep.Location = new System.Drawing.Point(199, 3);
            this.chkBlockBeep.Name = "chkBlockBeep";
            this.chkBlockBeep.Size = new System.Drawing.Size(86, 17);
            this.chkBlockBeep.TabIndex = 2;
            this.chkBlockBeep.Text = "屏蔽蜂鸣器";
            this.chkBlockBeep.UseVisualStyleBackColor = true;
            this.chkBlockBeep.CheckedChanged += new System.EventHandler(this.chkBlockBeep_CheckedChanged);
            //
            // chkManualInputForbidden
            //
            this.chkManualInputForbidden.AutoSize = true;
            this.chkManualInputForbidden.Location = new System.Drawing.Point(291, 3);
            this.chkManualInputForbidden.Name = "chkManualInputForbidden";
            this.chkManualInputForbidden.Size = new System.Drawing.Size(122, 17);
            this.chkManualInputForbidden.TabIndex = 4;
            this.chkManualInputForbidden.Text = "禁止手动输入条码";
            this.chkManualInputForbidden.UseVisualStyleBackColor = true;
            this.chkManualInputForbidden.CheckedChanged += new System.EventHandler(this.chkManualInputForbidden_CheckedChanged);
            //
            // btnLightSwitch
            //
            this.btnLightSwitch.Location = new System.Drawing.Point(419, 3);
            this.btnLightSwitch.Name = "btnLightSwitch";
            this.btnLightSwitch.Size = new System.Drawing.Size(75, 36);
            this.btnLightSwitch.TabIndex = 5;
            this.btnLightSwitch.Text = "日光灯开关";
            this.btnLightSwitch.UseVisualStyleBackColor = true;
            this.btnLightSwitch.Click += new System.EventHandler(this.btnLightSwitch_Click);
            //
            // M071_ShortcutFrm
            //
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Controls.Add(this.flowLayoutPanel1);
            this.Name = "M071_ShortcutFrm";
            this.Text = "M071_ShortcutFrm";
            this.flowLayoutPanel1.ResumeLayout(false);
            this.flowLayoutPanel1.PerformLayout();
            this.ResumeLayout(false);
        }
        #endregion
        private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
        private System.Windows.Forms.CheckBox chkBlockSaftyDoor;
        private System.Windows.Forms.CheckBox chkBlockSafetyBeam;
        private System.Windows.Forms.CheckBox chkBlockBeep;
        private System.Windows.Forms.CheckBox chkManualInputForbidden;
        private System.Windows.Forms.Button btnLightSwitch;
    }
}
src/Bro.M071.Process/UI/M071_ShortcutFrm.cs
@@ -6,6 +6,7 @@
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -17,6 +18,81 @@
        public M071_ShortcutFrm()
        {
            InitializeComponent();
            this.Load += (s, e) =>
              {
                  loadHandle.Set();
              };
        }
        ManualResetEventSlim loadHandle = new ManualResetEventSlim(false);
        M071Config Config => Process?.IConfig as M071Config;
        M071Process Process_M071 => Process as M071Process;
        protected override bool IsLogin
        {
            get => base.IsLogin;
            set
            {
                base.IsLogin = value;
                Task.Run(() =>
                {
                    if (loadHandle.Wait(1000))
                    {
                        this.Invoke(new Action(() =>
                        {
                            chkBlockSafetyBeam.Enabled = chkBlockSaftyDoor.Enabled = IsLogin;
                        }));
                    }
                });
            }
        }
        public override void OnProcessUpdated()
        {
            base.OnProcessUpdated();
            Task.Run(() =>
            {
                if (loadHandle.Wait(1000))
                {
                    this.Invoke(new Action(() =>
                    {
                        chkBlockBeep.Checked = Config.IsBeepBlocked;
                        chkBlockSafetyBeam.Checked = Config.IsSafetyBeamBlocked;
                        chkBlockSaftyDoor.Checked = Config.IsSafetyDoorBlocked;
                        chkManualInputForbidden.Checked = Config.IsBarcodeManulInputBlocked;
                    }));
                }
            });
        }
        private void chkBlockSaftyDoor_CheckedChanged(object sender, EventArgs e)
        {
            Config.IsSafetyDoorBlocked = chkBlockSaftyDoor.Checked;
        }
        private void chkBlockSafetyBeam_CheckedChanged(object sender, EventArgs e)
        {
            Config.IsSafetyBeamBlocked = chkBlockSafetyBeam.Checked;
        }
        private void chkBlockBeep_CheckedChanged(object sender, EventArgs e)
        {
            Config.IsBeepBlocked = chkBlockBeep.Checked;
        }
        private void chkManualInputForbidden_CheckedChanged(object sender, EventArgs e)
        {
            Config.IsBarcodeManulInputBlocked = chkManualInputForbidden.Checked;
        }
        bool isLightOn = false;
        private void btnLightSwitch_Click(object sender, EventArgs e)
        {
            isLightOn = !isLightOn;
            Process_M071.SwitchLight(isLightOn);
        }
    }
}
src/Bro.M071.Process/UI/M071_ShortcutFrm.resx
New file
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--
    Microsoft ResX Schema
    Version 2.0
    The primary goals of this format is to allow a simple XML format
    that is mostly human readable. The generation and parsing of the
    various data types are done through the TypeConverter classes
    associated with the data types.
    Example:
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
    There are any number of "resheader" rows that contain simple
    name/value pairs.
    Each data row contains a name, and value. The row also contains a
    type or mimetype. Type corresponds to a .NET class that support
    text/value conversion through the TypeConverter architecture.
    Classes that don't support this are serialized and stored with the
    mimetype set.
    The mimetype is used for serialized objects, and tells the
    ResXResourceReader how to depersist the object. This is currently not
    extensible. For a given mimetype the value must be set accordingly:
    Note - application/x-microsoft.net.object.binary.base64 is the format
    that the ResXResourceWriter will generate, however the reader can
    read any of the formats listed below.
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
</root>
src/Bro.Process/Bro.Process.csproj
@@ -168,4 +168,9 @@
    <Error Condition="!Exists('..\..\packages\PostSharp.6.2.7\build\PostSharp.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\PostSharp.6.2.7\build\PostSharp.targets'))" />
  </Target>
  <Import Project="..\..\packages\PostSharp.6.2.7\build\PostSharp.targets" Condition="Exists('..\..\packages\PostSharp.6.2.7\build\PostSharp.targets')" />
  <ProjectExtensions>
    <VisualStudio>
      <UserProperties setting_1json__JsonSchema="https://batect.dev/configSchema.json" />
    </VisualStudio>
  </ProjectExtensions>
</Project>
src/Bro.UI.Config/AdvancedPwdFrm.cs
@@ -76,5 +76,11 @@
                CheckInputPassword();
            }
        }
        private void btnExitLogin_Click(object sender, EventArgs e)
        {
            OnLoginOK?.Invoke(false);
            this.DialogResult = DialogResult.Abort;
        }
    }
}
src/Bro.UI.Config/AdvancedPwdFrm.designer.cs
@@ -32,11 +32,12 @@
            this.label1 = new System.Windows.Forms.Label();
            this.btnCancel = new System.Windows.Forms.Button();
            this.btnOK = new System.Windows.Forms.Button();
            this.btnExitLogin = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // txtPwd
            // 
            this.txtPwd.Font = new System.Drawing.Font("SimSun", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.txtPwd.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.txtPwd.Location = new System.Drawing.Point(126, 28);
            this.txtPwd.Name = "txtPwd";
            this.txtPwd.PasswordChar = '*';
@@ -47,7 +48,7 @@
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("SimSun", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label1.Font = new System.Drawing.Font("宋体", 10F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label1.Location = new System.Drawing.Point(32, 32);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(52, 14);
@@ -57,7 +58,7 @@
            // btnCancel
            // 
            this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.btnCancel.Font = new System.Drawing.Font("SimSun", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnCancel.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnCancel.Location = new System.Drawing.Point(208, 63);
            this.btnCancel.Name = "btnCancel";
            this.btnCancel.Size = new System.Drawing.Size(75, 23);
@@ -68,7 +69,7 @@
            // 
            // btnOK
            // 
            this.btnOK.Font = new System.Drawing.Font("SimSun", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnOK.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnOK.Location = new System.Drawing.Point(289, 63);
            this.btnOK.Name = "btnOK";
            this.btnOK.Size = new System.Drawing.Size(75, 23);
@@ -76,6 +77,18 @@
            this.btnOK.Text = "OK";
            this.btnOK.UseVisualStyleBackColor = true;
            this.btnOK.Click += new System.EventHandler(this.button2_Click);
            //
            // btnExitLogin
            //
            this.btnExitLogin.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.btnExitLogin.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.btnExitLogin.Location = new System.Drawing.Point(12, 63);
            this.btnExitLogin.Name = "btnExitLogin";
            this.btnExitLogin.Size = new System.Drawing.Size(75, 23);
            this.btnExitLogin.TabIndex = 2;
            this.btnExitLogin.Text = "退出登录";
            this.btnExitLogin.UseVisualStyleBackColor = true;
            this.btnExitLogin.Click += new System.EventHandler(this.btnExitLogin_Click);
            // 
            // AdvancedPwdFrm
            // 
@@ -85,6 +98,7 @@
            this.ClientSize = new System.Drawing.Size(388, 98);
            this.ControlBox = false;
            this.Controls.Add(this.btnOK);
            this.Controls.Add(this.btnExitLogin);
            this.Controls.Add(this.btnCancel);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.txtPwd);
@@ -103,5 +117,6 @@
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Button btnCancel;
        private System.Windows.Forms.Button btnOK;
        private System.Windows.Forms.Button btnExitLogin;
    }
}
src/Bro.UI.Config/MainFrm.cs
@@ -317,7 +317,7 @@
        private void OnLoginOK(bool isLogin)
        {
            IsLogin = true;
            IsLogin = isLogin;
        }
        #endregion
src/Bro.UI.Device.Winform/CtrlCameraRunBase.Designer.cs
@@ -27,8 +27,14 @@
            this.tsmiShowOpBar = new System.Windows.Forms.ToolStripMenuItem();
            this.tsmiShowElements = new System.Windows.Forms.ToolStripMenuItem();
            this.tsmiShowStatusBar = new System.Windows.Forms.ToolStripMenuItem();
            this.tsmiBtnExecuteOpConfig = new System.Windows.Forms.ToolStripButton();
            this.tscOpConfig = new System.Windows.Forms.ToolStripContainer();
            this.tsmiShowOpConfig = new System.Windows.Forms.ToolStripMenuItem();
            this.propGridOpConfig = new System.Windows.Forms.PropertyGrid();
            this.toolStripOperation.SuspendLayout();
            this.ctmsVisibleControl.SuspendLayout();
            this.tscOpConfig.ContentPanel.SuspendLayout();
            this.tscOpConfig.SuspendLayout();
            this.SuspendLayout();
            // 
            // toolStripOperation
@@ -41,7 +47,8 @@
            this.toolStripOperation.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.tssBtnCameraOp,
            this.tsTxtExposure,
            this.tsBtnModifyExposure});
            this.tsBtnModifyExposure,
            this.tsmiBtnExecuteOpConfig});
            this.toolStripOperation.Location = new System.Drawing.Point(38, 2);
            this.toolStripOperation.Name = "toolStripOperation";
            this.toolStripOperation.Size = new System.Drawing.Size(440, 28);
@@ -76,7 +83,7 @@
            // 
            this.tsTxtExposure.Font = new System.Drawing.Font("Microsoft YaHei UI", 9F);
            this.tsTxtExposure.Name = "tsTxtExposure";
            this.tsTxtExposure.Size = new System.Drawing.Size(100, 25);
            this.tsTxtExposure.Size = new System.Drawing.Size(100, 28);
            // 
            // tsBtnModifyExposure
            // 
@@ -84,7 +91,7 @@
            this.tsBtnModifyExposure.Image = ((System.Drawing.Image)(resources.GetObject("tsBtnModifyExposure.Image")));
            this.tsBtnModifyExposure.ImageTransparentColor = System.Drawing.Color.Magenta;
            this.tsBtnModifyExposure.Name = "tsBtnModifyExposure";
            this.tsBtnModifyExposure.Size = new System.Drawing.Size(60, 22);
            this.tsBtnModifyExposure.Size = new System.Drawing.Size(60, 25);
            this.tsBtnModifyExposure.Text = "修改曝光";
            this.tsBtnModifyExposure.Click += new System.EventHandler(this.tsBtnModifyExposure_Click);
            // 
@@ -94,9 +101,10 @@
            this.tsmiShowToolBar,
            this.tsmiShowOpBar,
            this.tsmiShowElements,
            this.tsmiShowStatusBar});
            this.tsmiShowStatusBar,
            this.tsmiShowOpConfig});
            this.ctmsVisibleControl.Name = "ctmsVisibleControl";
            this.ctmsVisibleControl.Size = new System.Drawing.Size(149, 92);
            this.ctmsVisibleControl.Size = new System.Drawing.Size(149, 114);
            // 
            // tsmiShowToolBar
            // 
@@ -130,11 +138,54 @@
            this.tsmiShowStatusBar.Text = "显示状态栏";
            this.tsmiShowStatusBar.CheckedChanged += new System.EventHandler(this.tsmiShowStatusBar_CheckedChanged);
            // 
            // tsmiBtnExecuteOpConfig
            //
            this.tsmiBtnExecuteOpConfig.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
            this.tsmiBtnExecuteOpConfig.Image = ((System.Drawing.Image)(resources.GetObject("tsmiBtnExecuteOpConfig.Image")));
            this.tsmiBtnExecuteOpConfig.ImageTransparentColor = System.Drawing.Color.Magenta;
            this.tsmiBtnExecuteOpConfig.Name = "tsmiBtnExecuteOpConfig";
            this.tsmiBtnExecuteOpConfig.Size = new System.Drawing.Size(84, 25);
            this.tsmiBtnExecuteOpConfig.Text = "执行操作配置";
            this.tsmiBtnExecuteOpConfig.Click += new System.EventHandler(this.tsmiBtnExecuteOpConfig_Click);
            //
            // tscOpConfig
            //
            //
            // tscOpConfig.ContentPanel
            //
            this.tscOpConfig.ContentPanel.Controls.Add(this.propGridOpConfig);
            this.tscOpConfig.ContentPanel.Size = new System.Drawing.Size(478, 175);
            this.tscOpConfig.Dock = System.Windows.Forms.DockStyle.Bottom;
            this.tscOpConfig.Location = new System.Drawing.Point(0, 265);
            this.tscOpConfig.Name = "tscOpConfig";
            this.tscOpConfig.Size = new System.Drawing.Size(478, 175);
            this.tscOpConfig.TabIndex = 1;
            this.tscOpConfig.Text = "toolStripContainer1";
            this.tscOpConfig.Visible = false;
            //
            // tsmiShowOpConfig
            //
            this.tsmiShowOpConfig.CheckOnClick = true;
            this.tsmiShowOpConfig.Name = "tsmiShowOpConfig";
            this.tsmiShowOpConfig.Size = new System.Drawing.Size(148, 22);
            this.tsmiShowOpConfig.Text = "显示操作配置";
            this.tsmiShowOpConfig.CheckedChanged += new System.EventHandler(this.tsmiShowOpConfig_CheckedChanged);
            //
            // propGridOpConfig
            //
            this.propGridOpConfig.Dock = System.Windows.Forms.DockStyle.Fill;
            this.propGridOpConfig.Location = new System.Drawing.Point(0, 0);
            this.propGridOpConfig.Name = "propGridOpConfig";
            this.propGridOpConfig.Size = new System.Drawing.Size(478, 175);
            this.propGridOpConfig.TabIndex = 0;
            this.propGridOpConfig.ToolbarVisible = false;
            //
            // CtrlCameraRunBase
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ContextMenuStrip = this.ctmsVisibleControl;
            this.Controls.Add(this.tscOpConfig);
            this.Controls.Add(this.toolStripOperation);
            this.Name = "CtrlCameraRunBase";
            this.Size = new System.Drawing.Size(478, 440);
@@ -142,6 +193,9 @@
            this.toolStripOperation.ResumeLayout(false);
            this.toolStripOperation.PerformLayout();
            this.ctmsVisibleControl.ResumeLayout(false);
            this.tscOpConfig.ContentPanel.ResumeLayout(false);
            this.tscOpConfig.ResumeLayout(false);
            this.tscOpConfig.PerformLayout();
            this.ResumeLayout(false);
        }
@@ -158,5 +212,9 @@
        private System.Windows.Forms.ToolStripMenuItem tsmiShowOpBar;
        private System.Windows.Forms.ToolStripMenuItem tsmiShowElements;
        private System.Windows.Forms.ToolStripMenuItem tsmiShowStatusBar;
        private System.Windows.Forms.ToolStripButton tsmiBtnExecuteOpConfig;
        private System.Windows.Forms.ToolStripMenuItem tsmiShowOpConfig;
        private System.Windows.Forms.ToolStripContainer tscOpConfig;
        private System.Windows.Forms.PropertyGrid propGridOpConfig;
    }
}
src/Bro.UI.Device.Winform/CtrlCameraRunBase.cs
@@ -1,8 +1,11 @@
using Bro.Common.Interface;
using Bro.Common.Factory;
using Bro.Common.Helper;
using Bro.Common.Interface;
using Bro.UI.Model.Winform;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace Bro.Common.Base.UI
@@ -46,6 +49,17 @@
            Camera.OnCameraOpModeChanged += Camera_OnCameraOpModeChanged;
            InitialToolBarVisible();
            string typeCode = Camera.GetType().GetCustomAttribute<DeviceAttribute>()?.TypeCode;
            if (string.IsNullOrWhiteSpace(typeCode))
            {
                propGridOpConfig.SelectedObject = OpConfig = new CameraOprerationConfigBase();
            }
            else
            {
                propGridOpConfig.SelectedObject = OpConfig = ConfigFactory.GetOperationConfig(typeCode);
            }
        }
        private readonly Dictionary<string, List<IShapeElement>> _eleBufferDict = new Dictionary<string, List<IShapeElement>>();
@@ -248,8 +262,13 @@
        {
            IsShowStatusBar = tsmiShowStatusBar.Checked;
        }
        private void tsmiShowOpConfig_CheckedChanged(object sender, EventArgs e)
        {
            tscOpConfig.Visible = tsmiShowOpConfig.Checked;
        }
        #endregion
        public IOperationConfig OpConfig { get; set; }
        public void UploadOperationConfig(IOperationConfig opConfig)
@@ -261,5 +280,10 @@
        {
            throw new NotImplementedException();
        }
        private void tsmiBtnExecuteOpConfig_Click(object sender, EventArgs e)
        {
            Camera.Snapshot(OpConfig);
        }
    }
}
src/Bro.UI.Device.Winform/CtrlCameraRunBase.resx
@@ -151,6 +151,21 @@
        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
  </data>
  <data name="tsmiBtnExecuteOpConfig.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
</value>
  </data>
  <metadata name="ctmsVisibleControl.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>127, 17</value>
  </metadata>
src/Bro.UI.Model.Winform/ElementBase.cs
@@ -243,16 +243,20 @@
            if (State == ElementState.MeasureDoneNG || State == ElementState.MeasureDoneOK)
                return;
            if (State == ElementState.MouseInSide)
            //if (State == ElementState.MouseInSide)
            //{
            //    State = ElementState.Selected;
            //}
            //else if (State == ElementState.Selected || State == ElementState.Moving)
            //{
            //    if (IsMouseInSide(p))
            //    {
            //        State = ElementState.MouseInSide;
            //    }
            //}
            if (IsMouseInSide(p))
            {
                State = ElementState.Selected;
            }
            else if (State == ElementState.Selected || State == ElementState.Moving)
            {
                if (IsMouseInSide(p))
                {
                    State = ElementState.MouseInSide;
                }
            }
        }
@@ -262,22 +266,59 @@
        public virtual void OnMouseDown(Point p)
        {
            switch (State)
            //switch (State)
            //{
            //    case ElementState.New:
            //        OnMouseDownWhenNew(p);
            //        break;
            //    case ElementState.MouseHover:
            //        break;
            //    case ElementState.MouseInSide:
            //        State = ElementState.Selected;
            //        break;
            //    case ElementState.Selected:
            //        _startPoint = p;
            //        State = ElementState.Moving;
            //        break;
            //    case ElementState.Normal:
            //        break;
            //}
            if (IsMouseCanMoveElement(p) && State == ElementState.Selected)
            {
                case ElementState.New:
                    OnMouseDownWhenNew(p);
                    break;
                case ElementState.MouseHover:
                    break;
                case ElementState.MouseInSide:
                    State = ElementState.Selected;
                    break;
                case ElementState.Selected:
                    _startPoint = p;
                    State = ElementState.Moving;
                    break;
                case ElementState.Normal:
                    break;
                State = ElementState.Moving;
            }
            else if (IsMouseCanStretchBottom(p) && State == ElementState.CanStretchBottom)
            {
                State = ElementState.StretchingBottom;
            }
            else if (IsMouseCanStretchTop(p) && State == ElementState.CanStretchTop)
            {
                State = ElementState.StretchingTop;
            }
            else if (IsMouseCanStretchLeft(p) && State == ElementState.CanStretchLeft)
            {
                State = ElementState.StretchingLeft;
            }
            else if (IsMouseCanStretchRight(p) && State == ElementState.CanStretchRight)
            {
                State = ElementState.StretchingRight;
            }
            else if (IsMouseCanStretchLeftLowerCorner(p) && State == ElementState.CanStretchLeftLowerCorner)
            {
                State = ElementState.StretchingLeftLowerCorner;
            }
            else if (IsMouseCanStretchLeftUpperCorner(p) && State == ElementState.CanStretchLeftUpperCorner)
            {
                State = ElementState.StretchingLeftUpperCorner;
            }
            else if (IsMouseCanStretchRightLowerCorner(p) && State == ElementState.CanStretchRightLowerCorner)
            {
                State = ElementState.StretchingRightLowerCorner;
            }
            else if (IsMouseCanStretchRightUpperCorner(p) && State == ElementState.CanStretchRightUpperCorner)
            {
                State = ElementState.StretchingRightUpperCorner;
            }
        }
@@ -289,27 +330,133 @@
                    OnMouseMoveWhenNew(p);
                    break;
                case ElementState.Selected:
                    if (IsMouseCanStretchLeft(p))
                    {
                        State = ElementState.CanStretchLeft;
                    }
                    else if (IsMouseCanStretchRight(p))
                    {
                        State = ElementState.CanStretchRight;
                    }
                    else if (IsMouseCanStretchTop(p))
                    {
                        State = ElementState.CanStretchTop;
                    }
                    else if (IsMouseCanStretchBottom(p))
                    {
                        State = ElementState.CanStretchBottom;
                    }
                    else if (IsMouseCanStretchLeftLowerCorner(p))
                    {
                        State = ElementState.CanStretchLeftLowerCorner;
                    }
                    else if (IsMouseCanStretchLeftUpperCorner(p))
                    {
                        State = ElementState.CanStretchLeftUpperCorner;
                    }
                    else if (IsMouseCanStretchRightLowerCorner(p))
                    {
                        State = ElementState.CanStretchRightLowerCorner;
                    }
                    else if (IsMouseCanStretchRightUpperCorner(p))
                    {
                        State = ElementState.CanStretchRightUpperCorner;
                    }
                    break;
                case ElementState.Moving:
                    _currentPoint = p;
                    Translate(_currentPoint.X - _startPoint.X, _currentPoint.Y - _startPoint.Y);
                    _startPoint = _currentPoint;
                    //Translate(_currentPoint.X - _startPoint.X, _currentPoint.Y - _startPoint.Y);
                    //_startPoint = _currentPoint;
                    Relocate(p);
                    break;
                case ElementState.MouseHover:
                case ElementState.MouseInSide:
                case ElementState.Normal:
                    if (IsMouseInSide(p))
                    //if (IsMouseInSide(p))
                    //{
                    //    State = ElementState.MouseInSide;
                    //}
                    //else if (IsMouseHover(p))
                    //{
                    //    State = ElementState.MouseHover;
                    //}
                    //else
                    //{
                    //    State = ElementState.Normal;
                    //}
                    break;
                case ElementState.CanStretchBottom:
                    if (!IsMouseCanStretchBottom(p))
                    {
                        State = ElementState.MouseInSide;
                        State = ElementState.Selected;
                    }
                    else if (IsMouseHover(p))
                    break;
                case ElementState.CanStretchTop:
                    if (!IsMouseCanStretchTop(p))
                    {
                        State = ElementState.MouseHover;
                        State = ElementState.Selected;
                    }
                    else
                    break;
                case ElementState.CanStretchLeft:
                    if (!IsMouseCanStretchLeft(p))
                    {
                        State = ElementState.Normal;
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.CanStretchRight:
                    if (!IsMouseCanStretchRight(p))
                    {
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.CanStretchLeftUpperCorner:
                    if (!IsMouseCanStretchLeftUpperCorner(p))
                    {
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.CanStretchLeftLowerCorner:
                    if (!IsMouseCanStretchLeftLowerCorner(p))
                    {
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.CanStretchRightLowerCorner:
                    if (!IsMouseCanStretchRightLowerCorner(p))
                    {
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.CanStretchRightUpperCorner:
                    if (!IsMouseCanStretchRightUpperCorner(p))
                    {
                        State = ElementState.Selected;
                    }
                    break;
                case ElementState.StretchingTop:
                    StretchTop(p);
                    break;
                case ElementState.StretchingBottom:
                    StretchBottom(p);
                    break;
                case ElementState.StretchingLeft:
                    StretchLeft(p);
                    break;
                case ElementState.StretchingRight:
                    StretchRight(p);
                    break;
                case ElementState.StretchingLeftLowerCorner:
                    StretchLeftLowerCorner(p);
                    break;
                case ElementState.StretchingLeftUpperCorner:
                    StretchLeftUpperCorner(p);
                    break;
                case ElementState.StretchingRightLowerCorner:
                    StretchRightLowerCorner(p);
                    break;
                case ElementState.StretchingRightUpperCorner:
                    StretchRightUpperCorner(p);
                    break;
            }
        }
@@ -319,15 +466,48 @@
            switch (State)
            {
                case ElementState.Moving:
                    //Calculate(null);
                    State = ElementState.Selected;
                    break;
                case ElementState.Selected:
                    //Calculate(null);
                    if (!IsMouseInSide(p))
                    {
                        State = ElementState.Normal;
                    }
                    break;
                case ElementState.StretchingBottom:
                    State = ElementState.CanStretchBottom;
                    break;
                case ElementState.StretchingLeft:
                    State = ElementState.CanStretchLeft;
                    break;
                case ElementState.StretchingRight:
                    State = ElementState.CanStretchRight;
                    break;
                case ElementState.StretchingTop:
                    State = ElementState.CanStretchTop;
                    break;
                case ElementState.StretchingLeftLowerCorner:
                    State = ElementState.CanStretchLeftLowerCorner;
                    break;
                case ElementState.StretchingLeftUpperCorner:
                    State = ElementState.CanStretchLeftUpperCorner;
                    break;
                case ElementState.StretchingRightUpperCorner:
                    State = ElementState.CanStretchRightUpperCorner;
                    break;
                case ElementState.StretchingRightLowerCorner:
                    State = ElementState.CanStretchRightLowerCorner;
                    break;
                default:
                    State = ElementState.Normal;
                    break;
            }
            AfterTranformOp();
        }
        public virtual void AfterTranformOp()
        {
        }
        #region 当基元状态为新建或可编辑时的鼠标操作动作
@@ -366,32 +546,84 @@
        public abstract bool IsIntersect(Rectangle rect);
        #region Move & Stretch & Move Anchor
        public virtual bool IsMouseCanMoveElement()
        public virtual bool IsMouseCanMoveElement(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchLeft()
        public virtual bool IsMouseCanStretchLeft(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchRight()
        public virtual bool IsMouseCanStretchRight(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchTop()
        public virtual bool IsMouseCanStretchTop(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchBottom()
        public virtual bool IsMouseCanStretchBottom(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanMoveAnchor()
        public virtual void StretchLeft(Point p)
        {
        }
        public virtual void StretchRight(Point p)
        {
        }
        public virtual void StretchTop(Point p)
        {
        }
        public virtual void StretchBottom(Point p)
        {
        }
        public virtual bool IsMouseCanStretchLeftUpperCorner(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchRightUpperCorner(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchLeftLowerCorner(Point p)
        {
            return false;
        }
        public virtual bool IsMouseCanStretchRightLowerCorner(Point p)
        {
            return false;
        }
        public virtual void StretchLeftUpperCorner(Point p)
        {
        }
        public virtual void StretchRightUpperCorner(Point p)
        {
        }
        public virtual void StretchLeftLowerCorner(Point p)
        {
        }
        public virtual void StretchRightLowerCorner(Point p)
        {
        }
        public virtual bool IsMouseCanMoveAnchor(Point p)
        {
            return false;
        }
@@ -402,6 +634,8 @@
        #region 变形操作
        public abstract void Translate(int x, int y);
        public virtual void Relocate(Point point) { }
        //public abstract void RotateAt(int x, int y, float degree);
        #endregion
src/Bro.UI.Model.Winform/UI/Canvas.cs
@@ -77,7 +77,7 @@
            set => stsStatus.Visible = value;
        }
        private async void OnMouseLocationUpdated(Point screenPoint, Point imagePoint, string colorDesc)
        private void OnMouseLocationUpdated(Point screenPoint, Point imagePoint, string colorDesc)
        {
            //await Task.Run(() => tsslLocation.Text = $"屏幕坐标X:{screenPoint.X},Y:{screenPoint.Y}    图片坐标X:{imagePoint.X},Y:{imagePoint.Y}   颜色:{colorDesc}");
            this.Invoke(new Action(() =>
@@ -381,17 +381,17 @@
        private void tsmiUnselectElements_Click(object sender, EventArgs e)
        {
            if (MouseState == MouseState.SelectedElement)
            {
                MouseState = MouseState.Normal;
            //if (MouseState == MouseState.SelectedElement)
            //{
            //    MouseState = MouseState.Normal;
                //Elements.ForEach(ele =>
                foreach (IShapeElement ele in Elements)
                {
                    ele.State = ElementState.Normal;
                }
                //);
            }
            //    //Elements.ForEach(ele =>
            //    foreach (IShapeElement ele in Elements)
            //    {
            //        ele.State = ElementState.Normal;
            //    }
            //    //);
            //}
        }
        #endregion
src/Bro.UI.Model.Winform/UI/CanvasImage.cs
@@ -30,6 +30,8 @@
            MouseDown += Canvas_MouseDown;
            MouseMove += Canvas_MouseMove;
            MouseUp += Canvas_MouseUp;
            EventRouter.ChangeElementsMouseState = OnElementChangeMouseState;
        }
        #region Event
@@ -261,10 +263,12 @@
                        MouseState = MouseState.New;
                        break;
                    case ElementState.Selected:
                        MouseState = MouseState.SelectedElement;
                        CurrentElementId = ele.ID;
                        Cursor = Cursors.Default;
                        break;
                    case ElementState.Moving:
                        MouseState = MouseState.MoveElement;
                        Cursor = Cursors.NoMove2D;
                        break;
                    case ElementState.MouseInSide:
                        MouseState = MouseState.InSideElement;
@@ -272,14 +276,67 @@
                    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;
                }
                if (MouseState == MouseState.SelectedElement)
                {
                    CurrentElementId = ele.ID;
                }
            }
            else
@@ -328,6 +385,7 @@
        }
        Point startPoint, currentPoint;
        bool _isMouseBtnPressing = false;
        private void Canvas_MouseDown(object sender, MouseEventArgs e)
        {
@@ -335,49 +393,22 @@
            if (e.Button == MouseButtons.Left)
            {
                _isMouseBtnPressing = true;
                switch (MouseState)
                {
                    case MouseState.Normal:
                        //if (DrawTemplate == null && string.IsNullOrWhiteSpace(CurrentElementId))
                        //{
                        //    this.Cursor = Cursors.Hand;
                        //    startPoint = e.Location;
                        //}
                        //else
                        //{
                        //    MouseState = MouseState.New;
                        //}
                        MouseState = MouseState.MovingAll;
                        startPoint = e.Location;
                        //Elements.ForEach(ele =>
                        foreach (IShapeElement ele in Elements)
                        {
                            ele.State = ElementState.Normal;
                            ele.OnMouseDown(p);
                        }
                        //);
                        break;
                    case MouseState.StretchingLeft:
                        break;
                    case MouseState.StretchingRight:
                        break;
                    case MouseState.StretchingUp:
                    case MouseState.StretchingTop:
                        break;
                    case MouseState.StretchingDown:
                    case MouseState.StretchingBottom:
                        break;
                    case MouseState.MoveElement:
                        break;
                    case MouseState.SelectedElement:
                        //MouseState = MouseState.MoveElement;
                        startPoint = e.Location;
                        //Elements.ForEach(ele =>
                        foreach (IShapeElement ele in Elements)
                        {
                            ele.OnMouseDown(p);
                        }
                        //);
                        break;
                    case MouseState.HoverElement:
                    case MouseState.InSideElement:
@@ -392,26 +423,16 @@
                        break;
                }
                //if (DrawTemplate == null)
                //{
                //    this.Cursor = Cursors.Hand;
                //    startPoint = e.Location;
                //}
                //Point p = ToMapPoint(e.Location);
                //Elements.ForEach(ele =>
                //{
                //    ele.State = ElementState.Normal;
                //    ele.OnMouseDown(p);
                //});
                //DrawTemplate?.OnMouseDown(p);
                foreach (IShapeElement ele in Elements)
                {
                    ele.OnMouseDown(p);
                }
            }
        }
        private void Canvas_MouseUp(object sender, MouseEventArgs e)
        {
            _isMouseBtnPressing = false;
            switch (MouseState)
            {
                case MouseState.Normal:
@@ -424,9 +445,9 @@
                    break;
                case MouseState.StretchingRight:
                    break;
                case MouseState.StretchingUp:
                case MouseState.StretchingTop:
                    break;
                case MouseState.StretchingDown:
                case MouseState.StretchingBottom:
                    break;
                case MouseState.MoveElement:
                    //MouseState = MouseState.SelectedElement;
@@ -443,7 +464,6 @@
                case MouseState.SelectionZoneDoing:
                    MouseState = MouseState.SelectionZone;
                    //Elements.ForEach(ele =>
                    foreach (IShapeElement ele in Elements)
                    {
                        if (ele.IsIntersect(_selectionRect))
@@ -451,7 +471,6 @@
                            ele.State = ElementState.Selected;
                        }
                    }
                    //);
                    break;
            }
@@ -460,12 +479,10 @@
            Point p = ToMapPoint(e.Location);
            DrawTemplate?.OnMouseUp(p);
            //Elements.ForEach(ele =>
            foreach (IShapeElement ele in Elements)
            {
                ele.OnMouseUp(p);
            }
            //);
        }
        private void Canvas_MouseMove(object sender, MouseEventArgs e)
@@ -475,26 +492,26 @@
            switch (MouseState)
            {
                case MouseState.Normal:
                    //Elements.ForEach(u =>
                    //{
                    //    u.OnMouseMove(p);
                    //});
                    {
                        if (_isMouseBtnPressing)
                        {
                            currentPoint = e.Location;
                            Point p1 = ToMapPoint(startPoint);
                            Point 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.StretchingUp:
                case MouseState.StretchingTop:
                    break;
                case MouseState.StretchingDown:
                case MouseState.StretchingBottom:
                    break;
                case MouseState.MoveElement:
                    //Elements.ForEach(ele =>
                    foreach (IShapeElement ele in Elements)
                    {
                        ele.OnMouseMove(p);
                    }
                    //);
                    break;
                case MouseState.HoverElement:
                case MouseState.InSideElement:
@@ -504,13 +521,6 @@
                case MouseState.Editing:
                    break;
                case MouseState.MovingAll:
                    {
                        currentPoint = e.Location;
                        Point p1 = ToMapPoint(startPoint);
                        Point p2 = ToMapPoint(currentPoint);
                        Matrix.Translate(p2.X - p1.X, p2.Y - p1.Y);
                        startPoint = e.Location;
                    }
                    break;
                case MouseState.SelectionZoneDoing:
                    {
@@ -529,17 +539,6 @@
                    break;
            }
            //if (this.Cursor == Cursors.Hand)
            //{
            //    currentPoint = e.Location;
            //    Point p1 = ToMapPoint(startPoint);
            //    Point p2 = ToMapPoint(currentPoint);
            //    Matrix.Translate(p2.X - p1.X, p2.Y - p1.Y);
            //    startPoint = e.Location;
            //}
            //DisplayMouseLocation(e.Location);
            Point 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)
@@ -550,12 +549,10 @@
            if (MouseState != MouseState.SelectionZoneDoing)
            {
                //Elements.ForEach(u =>
                foreach (IShapeElement ele in Elements)
                {
                    ele.OnMouseMove(p);
                }
                //);
            }
            Invalidate();
@@ -569,7 +566,7 @@
            {
                switch (MouseState)
                {
                    case MouseState.SelectedElement:
                    //case MouseState.SelectedElement:
                    case MouseState.HoverElement:
                    case MouseState.InSideElement:
                    case MouseState.MoveElement:
@@ -587,7 +584,7 @@
            }
            else
            {
                if (MouseState == MouseState.SelectedElement)
                //if (MouseState == MouseState.SelectedElement)
                {
                    MouseState = MouseState.Normal;
@@ -702,22 +699,22 @@
        #region 按键操作
        public void OnCanvasKeyPressed(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == 27)  //Esc
            {
                if (MouseState == MouseState.SelectedElement)
                {
                    MouseState = MouseState.Normal;
            //if (e.KeyChar == 27)  //Esc
            //{
            //    //if (MouseState == MouseState.SelectedElement)
            //    {
            //        MouseState = MouseState.Normal;
                    //Elements.ForEach(ele =>
                    foreach (IShapeElement ele in Elements)
                    {
                        ele.State = ElementState.Normal;
                    }
                    //);
                }
            }
            //        //Elements.ForEach(ele =>
            //        foreach (IShapeElement ele in Elements)
            //        {
            //            ele.State = ElementState.Normal;
            //        }
            //        //);
            //    }
            //}
            Invalidate();
            //Invalidate();
        }
        public void OnCanvasKeyDown(object sender, KeyEventArgs e)
@@ -741,7 +738,7 @@
                    Elements.Remove(Elements.FirstOrDefault(u => u.ID == CurrentElementId));
                    break;
                case Keys.Escape:
                    if (MouseState == MouseState.SelectedElement)
                    //if (MouseState == MouseState.SelectedElement)
                    {
                        MouseState = MouseState.Normal;
src/Bro.UI.Model.Winform/UI/DockContent/MenuFrmBase.cs
@@ -2,6 +2,7 @@
using Bro.Common.Interface;
using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
@@ -23,11 +24,14 @@
                //if (process != value)
                {
                    process = value;
                    _constructionDoneHandle.Wait();
                    OnProcessUpdated();
                }
            }
        }
        ManualResetEventSlim _constructionDoneHandle = new ManualResetEventSlim(false);
        public MenuFrmBase()
        {
            InitializeComponent();
@@ -37,6 +41,8 @@
            {
                FormClosing += MenuFrmBase_FormClosing;
            }
            _constructionDoneHandle.Set();
        }
        protected virtual void MenuFrmBase_FormClosing(object sender, FormClosingEventArgs e)
@@ -75,7 +81,7 @@
        #endregion
        #region Login
        protected bool IsLogin { get; set; }
        protected virtual bool IsLogin { get; set; }
        public virtual void SetLoginStatus(bool isLogin)
        {