C3204
2025-12-18 d85cbf0ccd61d95b96695756e0c90db8b7679545
添加项目文件。
已添加415个文件
102382 ■■■■■ 文件已修改
LB_SmartVision/.cr/personal/FavoritesList/List.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Form1.Designer.cs 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Form1.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Form1.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/CreateProductForm.Designer.cs 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/CreateProductForm.cs 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/CreateProductForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.Designer.cs 509 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.cs 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.Designer.cs 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.cs 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.Designer.cs 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.Designer.cs 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.cs 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.Designer.cs 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.cs 211 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.Designer.cs 251 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.cs 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.Designer.cs 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.Designer.cs 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MyPage.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/MyPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.Designer.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.cs 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.Designer.cs 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.cs 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.resx 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.Designer.cs 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.Designer.cs 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.resx 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.Designer.cs 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.cs 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.Designer.cs 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.cs 404 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/ControlStateManager.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.Designer.cs 250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.cs 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.Designer.cs 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.cs 257 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.Designer.cs 341 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.cs 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.Designer.cs 172 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.cs 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.Designer.cs 322 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.cs 334 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.Designer.cs 372 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.cs 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.Designer.cs 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/GlobalVar.cs 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LB_Collections.cs 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LB_SmartVision.csproj 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LB_SmartVision.sln 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LB_SqlCommand.cs 573 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantoushangfangxiangshang.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouxiafangxiangxia.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouyoufangxiangyou.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouzuofangxiangzuo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-xinzengxinzeng.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-zhuangtailoudou.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-APPjianpan.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-bangzhuzhongxin.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-caogaoxiang.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-chakanxiangqing.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-chexiao.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-duihao.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-fangkongquanpeizhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-fuzhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-gengduo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanbi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guankongpeizhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanlian.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanzhu.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jia.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jian.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantoushang.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouxia.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouyou-1.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouyou.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouzuo-1.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouzuo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiemi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jieshu.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jinzhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-mima.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pinglun.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pizhu.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pizhuxinxi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-qidongyujing.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-qiehuan.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shaixuan.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shanchu.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shangchuan.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shezhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shipinpeizhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shousuo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shouzhe.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuangjiantouyou.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuangjiantouzuo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuaxin.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-sousuo.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuisong.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuisongjilu.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuozhuaizhongxin.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-weiguanlian.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-xiazai.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhankai.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhiding.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhongqi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-ziyuanpeizhi.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/LOGO/logo.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/ProcessRun/ExpressionTreeMappingEngine.cs 362 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/ProcessRun/ProcessContext.cs 698 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/ProcessRun/ProcessRunBll.cs 958 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Program.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Properties/Resources.Designer.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Properties/Resources.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/README.md 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Tool/ObservableConcurrentDictionary.cs 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Tool/OperateIniHelper.cs 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/Tool/Tool.cs 1134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/VisionForm.Designer.cs 369 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/VisionForm.cs 997 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/VisionForm.resx 1080 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/logo.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/ref/halcondotnet.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/CameraUserRole.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/Data/StateIcon.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/DeviceType.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/LB_SmartVisionCameraDevice.csproj 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/PHM6000/CaliModel.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/PHM6000/CaliOutLine.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/PHM6000/PHM6000Sensor.cs 1230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/PHM6000/PHM6000SensorConfig.cs 1055 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/SensorManager.cs 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/ref/PHM6000.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/ref/PHM6000API.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/ref/PHM6000API.lib 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/ref/Pilot2D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraDevice/ref/PointCloud3D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/LB_SmartVisionCameraSDK.csproj 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/PHM6000Profiler.cs 951 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/Pilot2D.cs 529 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/Point.cs 265 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/ProfilerData.cs 771 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PHM6000/SysCalibration.cs 761 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/PclEntry.cs 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/ref/PHM6000.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/ref/PHM6000API.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/ref/PHM6000API.lib 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/ref/Pilot2D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCameraSDK/ref/PointCloud3D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/AESHelper.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/AsyncLogHelper.cs 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/CommonVar.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/ConfigManager.cs 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/DiskInfoHelper.cs 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/DynamicPermissionObject.cs 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/DynamicPropertyDescriptor.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/Fun.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/LB_SmartVisionCommon.csproj 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/LogHelper.cs 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/NetworkDiagnostics.cs 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/NetworkMonitor.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/NetworkTester.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/PermissionAttribute.cs 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/PermissionPropertyDescriptor.cs 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/PropertySorter.cs 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/UserData.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionCommon/UserManager.cs 311 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/App.config 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/App.xaml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/App.xaml.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/AssemblyInfo.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/ICommonData_Loading.cs 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/LB_SmartVisionLoginUI.csproj 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/MainWindow.xaml 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/MainWindow.xaml.cs 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/01.JPG 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/02.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/03.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/04.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/05.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/06.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/07.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/favicon.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/lanbao.jpg 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/logo.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/logo_h.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/images/键盘.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/lanbao.jpg 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/logo.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVisionLoginUI/logo_h.png 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Form1.Designer.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Form1.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Form1.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Forms/RenameForm.Designer.cs 262 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Forms/RenameForm.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Forms/RenameForm.resx 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/LB_VisionControl.csproj 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Program.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Properties/Resources.Designer.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/Properties/Resources.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ROI.cs 580 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ClassFileList.Designer.cs 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ClassFileList.cs 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ClassFileList.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/CommConfig.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/CommandRun.cs 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/CompliReslut.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ComplieBuilder.cs 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ComplieType.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ComplieUI.Designer.cs 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ComplieUI.cs 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ComplieUI.resx 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ConsoleTextBox.cs 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ConsoleTextBox.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ContextMenuStripEx.cs 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/EditHeightLight.cs 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/AutocompleteItem.cs 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/AutocompleteMenu.cs 597 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Char.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/CommandManager.cs 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Commands.cs 724 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Export.cs 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.Designer.cs 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.cs 5473 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FileTextSource.cs 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.Designer.cs 215 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.cs 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.Designer.cs 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/LimitedStack.cs 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Line.cs 356 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/LinesAccessor.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Place.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/PlatformType.cs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Range.cs 1330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.Designer.cs 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.cs 169 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/Style.cs 410 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/SyntaxDescriptor.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/SyntaxHighlighter.cs 710 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/TextSource.cs 329 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/TypeDescriptor.cs 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/FastColorTextBox/VisualMarker.cs.cs 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/KeyWordsAuto.cs 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/KeysWordCMDAuto.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditControl.Designer.cs 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditControl.cs 366 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditControl.resx 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditForm.Designer.cs 463 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditForm.cs 510 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/ScriptEditForm.resx 1657 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ScriptEditControl/csharp.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserHSmartWindowControl.Designer.cs 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserHSmartWindowControl.cs 1174 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserHSmartWindowControl.resx 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserItem.Designer.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserItem.cs 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserItem.resx 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/UserPictureBox.cs 481 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionControl/ref/halcondotnet.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowConnection.cs 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowEnum.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowNode.cs 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowNodeEditor.Designer.cs 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowNodeEditor.cs 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowNodeEditor.resx 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowPanel.cs 1463 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/FlowSerializer.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/IFlowContext.cs 680 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/LB_VisionFlowNode.csproj 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/MainForm.Designer.cs 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/MainForm.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/MainForm.resx 286 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/Program.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/RenameForm.Designer.cs 261 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/RenameForm.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionFlowNode/RenameForm.resx 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithm.cs 5656 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.Designer.cs 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.cs 278 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestTool.cs 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.Designer.cs 515 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.cs 317 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobTool.cs 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.Designer.cs 1419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.cs 445 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HCalibTool/BaseCalib.cs 272 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HCalibTool/HCaltab.cs 555 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dTool.cs 329 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.Designer.cs 674 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.cs 325 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.resx 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineTool.cs 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.Designer.cs 860 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.cs 424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.resx 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelTool.cs 705 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.Designer.cs 1849 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.cs 1459 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelTool.cs 453 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.Designer.cs 713 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.cs 506 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.resx 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.Designer.cs 196 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.cs 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/Halcon/HDevelopExport.cs 8637 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobTool.cs 408 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.Designer.cs 1026 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.cs 349 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineTool.cs 817 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.Designer.cs 860 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.cs 424 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.resx 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelTool.cs 921 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.Designer.cs 1807 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.cs 1249 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.resx 129 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs 861 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.cs 660 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/2DCameraForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/BaseCamera.cs 299 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/CameraConfig.cs 315 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Cameras/ICamera.cs 312 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/BaseCommunicator.cs 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/CommunicatorCollections.cs 224 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/CommunicatorConfig.cs 243 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/CommunicatorForm.Designer.cs 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/CommunicatorForm.cs 353 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/CommunicatorForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/ICommunicator.cs 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/TCom/LocalMonitor.cs 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/TCom/TCPClient.cs 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/TCom/TCPServer.cs 231 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/TCom/UARTPort.cs 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Communicators/UserCommunicator/T306Command/T306CommandTool.cs 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarControl.Designer.cs 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarControl.cs 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarControl.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarForm.Designer.cs 203 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarForm.cs 160 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Forms/GlobalVarForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/IProcess.cs 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/LB_VisionProcesses.csproj 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/MainForm.Designer.cs 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/MainForm.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/MainForm.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/PluginInfo.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/PluginLoadContext.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/PluginManager.cs 432 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessAttribute.cs 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessCollections.cs 324 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessEditForm.Designer.cs 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessEditForm.cs 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessEditForm.resx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessInfo.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ProcessParams.cs 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/BaseProcess.cs 336 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/DelayTime.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/RecordTool/RecordTool.cs 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/ScriptTool/ScriptTool.cs 478 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.Designer.cs 330 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.cs 142 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.resx 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Program.cs 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Properties/Resources.Designer.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/Properties/Resources.resx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/logo.ico 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/CLIDelegate.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/MVSDK_Net.XML 2589 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/MVSDK_Net.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/PHM6000.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/PHM6000API.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/PHM6000API.lib 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/Pilot2D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/PointCloud3D.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/ThridLibray.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_VisionProcesses/ref/halcondotnet.dll 补丁 | 查看 | 原始文档 | blame | 历史
LB_SmartVision/.cr/personal/FavoritesList/List.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Root Type="DevExpress.CodeRush.Foundation.CodePlaces.Options.FavoritesListContainer">
  <Options Language="Neutral">
    <Groups />
  </Options>
</Root>
LB_SmartVision/Form1.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,90 @@
namespace LB_SmartVision
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            materialTabControl1 = new MaterialSkin.Controls.MaterialTabControl();
            tabPage1 = new TabPage();
            tabPage2 = new TabPage();
            materialTabControl1.SuspendLayout();
            SuspendLayout();
            //
            // materialTabControl1
            //
            materialTabControl1.Controls.Add(tabPage1);
            materialTabControl1.Controls.Add(tabPage2);
            materialTabControl1.Depth = 0;
            materialTabControl1.Dock = DockStyle.Fill;
            materialTabControl1.Font = new Font("Microsoft YaHei UI", 12F);
            materialTabControl1.Location = new Point(0, 0);
            materialTabControl1.MouseState = MaterialSkin.MouseState.HOVER;
            materialTabControl1.Name = "materialTabControl1";
            materialTabControl1.SelectedIndex = 0;
            materialTabControl1.Size = new Size(800, 450);
            materialTabControl1.TabIndex = 0;
            //
            // tabPage1
            //
            tabPage1.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Pixel);
            tabPage1.Location = new Point(4, 30);
            tabPage1.Name = "tabPage1";
            tabPage1.Padding = new Padding(3);
            tabPage1.Size = new Size(792, 416);
            tabPage1.TabIndex = 0;
            tabPage1.Text = "tabPage1";
            tabPage1.UseVisualStyleBackColor = true;
            //
            // tabPage2
            //
            tabPage2.Location = new Point(4, 30);
            tabPage2.Name = "tabPage2";
            tabPage2.Padding = new Padding(3);
            tabPage2.Size = new Size(792, 416);
            tabPage2.TabIndex = 1;
            tabPage2.Text = "tabPage2";
            tabPage2.UseVisualStyleBackColor = true;
            //
            // Form1
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(800, 450);
            Controls.Add(materialTabControl1);
            Name = "Form1";
            Text = "Form1";
            materialTabControl1.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private MaterialSkin.Controls.MaterialTabControl materialTabControl1;
        private TabPage tabPage1;
        private TabPage tabPage2;
    }
}
LB_SmartVision/Form1.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }
}
LB_SmartVision/Form1.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/CreateProductForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,185 @@
using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms
{
    partial class CreateProductForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateProductForm));
            uiLabel1 = new Label();
            uiLabel2 = new Label();
            uiButtonCancel = new AirButton();
            uiButtonCreate = new AirButton();
            uiButtonTest = new AirButton();
            uiTextBoxProductName = new TextBox();
            uiComboBoxProducts = new ComboBox();
            themeForm1 = new ReaLTaiizor.Forms.ThemeForm();
            SuspendLayout();
            //
            // uiLabel1
            //
            uiLabel1.Font = new Font("宋体", 12F);
            uiLabel1.ForeColor = SystemColors.Control;
            uiLabel1.Location = new Point(120, 97);
            uiLabel1.Name = "uiLabel1";
            uiLabel1.Size = new Size(100, 23);
            uiLabel1.TabIndex = 1;
            uiLabel1.Text = "复制源";
            //
            // uiLabel2
            //
            uiLabel2.Font = new Font("宋体", 12F);
            uiLabel2.ForeColor = SystemColors.Control;
            uiLabel2.Location = new Point(120, 163);
            uiLabel2.Name = "uiLabel2";
            uiLabel2.Size = new Size(100, 23);
            uiLabel2.TabIndex = 2;
            uiLabel2.Text = "产品名";
            //
            // uiButtonCancel
            //
            uiButtonCancel.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            uiButtonCancel.Font = new Font("宋体", 12F);
            uiButtonCancel.Image = null;
            uiButtonCancel.Location = new Point(343, 234);
            uiButtonCancel.MinimumSize = new Size(1, 1);
            uiButtonCancel.Name = "uiButtonCancel";
            uiButtonCancel.NoRounding = false;
            uiButtonCancel.Size = new Size(100, 35);
            uiButtonCancel.TabIndex = 4;
            uiButtonCancel.Text = "取消";
            uiButtonCancel.Transparent = false;
            uiButtonCancel.Click += uiButtonCancel_Click;
            //
            // uiButtonCreate
            //
            uiButtonCreate.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            uiButtonCreate.Enabled = false;
            uiButtonCreate.Font = new Font("宋体", 12F);
            uiButtonCreate.Image = null;
            uiButtonCreate.Location = new Point(187, 234);
            uiButtonCreate.MinimumSize = new Size(1, 1);
            uiButtonCreate.Name = "uiButtonCreate";
            uiButtonCreate.NoRounding = false;
            uiButtonCreate.Size = new Size(100, 35);
            uiButtonCreate.TabIndex = 9;
            uiButtonCreate.Text = "创建";
            uiButtonCreate.Transparent = false;
            uiButtonCreate.Click += uiButtonCreate_Click;
            //
            // uiButtonTest
            //
            uiButtonTest.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            uiButtonTest.Font = new Font("宋体", 12F);
            uiButtonTest.Image = null;
            uiButtonTest.Location = new Point(31, 234);
            uiButtonTest.MinimumSize = new Size(1, 1);
            uiButtonTest.Name = "uiButtonTest";
            uiButtonTest.NoRounding = false;
            uiButtonTest.Size = new Size(100, 35);
            uiButtonTest.TabIndex = 10;
            uiButtonTest.Text = "测试";
            uiButtonTest.Transparent = false;
            uiButtonTest.Click += uiButtonTest_Click;
            //
            // uiTextBoxProductName
            //
            uiTextBoxProductName.Font = new Font("宋体", 12F);
            uiTextBoxProductName.ForeColor = Color.Black;
            uiTextBoxProductName.Location = new Point(227, 157);
            uiTextBoxProductName.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxProductName.MinimumSize = new Size(1, 16);
            uiTextBoxProductName.Name = "uiTextBoxProductName";
            uiTextBoxProductName.Size = new Size(150, 26);
            uiTextBoxProductName.TabIndex = 12;
            uiTextBoxProductName.Text = "新产品";
            uiTextBoxProductName.TextChanged += uiTextBoxProductName_TextChanged;
            //
            // uiComboBoxProducts
            //
            uiComboBoxProducts.FormattingEnabled = true;
            uiComboBoxProducts.Location = new Point(226, 95);
            uiComboBoxProducts.Name = "uiComboBoxProducts";
            uiComboBoxProducts.Size = new Size(151, 25);
            uiComboBoxProducts.TabIndex = 13;
            uiComboBoxProducts.MouseClick += uiComboBoxProducts_MouseClick;
            //
            // themeForm1
            //
            themeForm1.BackColor = Color.FromArgb(32, 41, 50);
            themeForm1.Dock = DockStyle.Fill;
            themeForm1.Font = new Font("Microsoft Sans Serif", 9F);
            themeForm1.Image = (Image)resources.GetObject("themeForm1.Image");
            themeForm1.Location = new Point(0, 0);
            themeForm1.Name = "themeForm1";
            themeForm1.Padding = new Padding(10, 70, 10, 9);
            themeForm1.RoundCorners = true;
            themeForm1.Sizable = true;
            themeForm1.Size = new Size(507, 309);
            themeForm1.SmartBounds = true;
            themeForm1.StartPosition = FormStartPosition.WindowsDefaultLocation;
            themeForm1.TabIndex = 14;
            themeForm1.Text = "创建产品";
            //
            // CreateProductForm
            //
            AutoScaleMode = AutoScaleMode.None;
            BackColor = Color.FromArgb(32, 41, 50);
            ClientSize = new Size(507, 309);
            ControlBox = false;
            Controls.Add(uiComboBoxProducts);
            Controls.Add(uiTextBoxProductName);
            Controls.Add(uiButtonTest);
            Controls.Add(uiButtonCreate);
            Controls.Add(uiButtonCancel);
            Controls.Add(uiLabel2);
            Controls.Add(uiLabel1);
            Controls.Add(themeForm1);
            ForeColor = SystemColors.Control;
            FormBorderStyle = FormBorderStyle.None;
            MaximizeBox = false;
            MinimizeBox = false;
            MinimumSize = new Size(261, 61);
            Name = "CreateProductForm";
            Text = "创建产品";
            TransparencyKey = Color.Fuchsia;
            ResumeLayout(false);
            PerformLayout();
        }
        #endregion
        private Label uiLabel1;
        private Label uiLabel2;
        private ReaLTaiizor.Controls.AirButton uiButtonCancel;
        private ReaLTaiizor.Controls.AirButton uiButtonCreate;
        private ReaLTaiizor.Controls.AirButton uiButtonTest;
        private TextBox uiTextBoxProductName;
        private ComboBox uiComboBoxProducts;
        private ReaLTaiizor.Forms.ThemeForm themeForm1;
    }
}
LB_SmartVision/Forms/CreateProductForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,93 @@

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using ReaLTaiizor.Forms;
using RJCP.IO.Ports;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace LB_SmartVision.Forms
{
    public partial class CreateProductForm : Form
    {
        public List<string> listDatabaseName { get; set; }
        public bool bCreate = false;
        public CreateProductForm(List<string> listDatabaseNam = null)
        {
            InitializeComponent();
            // ç¦æ­¢ä¿®æ”¹çª—口大小
            //this.FormBorderStyle = FormBorderStyle.FixedDialog;
            uiButtonCreate.Enabled = false;
            if (listDatabaseNam == null)
                listDatabaseNam = LB_SqlCommand.GetUserDatabases();
            this.listDatabaseName = listDatabaseNam;
        }
        private void uiButtonTest_Click(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products);
            List<string> lstProduct = (Products.Split(',')).ToList();
            if (lstProduct.Contains(uiTextBoxProductName.Text))
                MessageBox.Show($"产品[{uiTextBoxProductName.Text}]已存在!", "异常");
            else
                uiButtonCreate.Enabled = true;
        }
        private void uiButtonCreate_Click(object sender, EventArgs e)
        {
            if (LB_SmartVision.Tool.Tool.CopyDirectory(Path.Combine(GlobalVar.strApplicationPath + "所有产品\\", GlobalVar.strProductName)
                , Path.Combine(GlobalVar.strApplicationPath + "所有产品\\", uiTextBoxProductName.Text)))
            {
                LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products);
                List<string> lstProduct = (Products.Split(',')).ToList();
                lstProduct.Add(uiTextBoxProductName.Text);
                LB_SmartVision.Tool.Tool.WriteConfig("产品列表", string.Join(",", lstProduct));
                MessageBox.Show($"创建产品[{uiTextBoxProductName.Text}]成功!");
                this.Close();
            }
        }
        private void uiButtonCancel_Click(object sender, EventArgs e)
        {
            bCreate = false;
            this.Close();
        }
        private void uiComboBoxProducts_MouseClick(object sender, MouseEventArgs e)
        {
            uiButtonCreate.Enabled = false;
            uiComboBoxProducts.Items.Clear();
            uiComboBoxProducts.Items.Add("无");
            LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products);
            List<string> lstProduct = (Products.Split(',')).ToList();
            foreach (string DatabaseName in lstProduct)
                uiComboBoxProducts.Items.Add(DatabaseName);
        }
        private void uiTextBoxProductName_TextChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
        }
    }
}
LB_SmartVision/Forms/CreateProductForm.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
<?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>
  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <data name="themeForm1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
        wgAADsIBFShKgAAAA+JJREFUWEftVkuIHGUQbt34iMEoq2S2q3p3yTJsuqpnJ+L6WBRdwaigohfFgEou
        BkVBUPCBCEG8BXNQ48GLeImCehIJxMsqhsSZruod46K4HtSIGjU+4iOr0c1I9fSsM3/PLNtCPO0H36m/
        evz/X11VnreKVRTAHPOZumkY6lFwqURws3BwZ8ywTQnuiCP/+iTCzY1qaUPzdm/Atf3PaHre6XPsjyQM
        2xLGV4XwIyX4QRj+UMK/lPFvJTyhBMeV8IgQvmRJuH4Ko+l5p9UjGBbCJ5RxTgj+VMZmXxKcSAjekHE/
        NNs5DgaTKLinEQYVO4Trf1mkV81wixLUslPmA3bzF2XcKeP+hWY/u3n0fCXcrQwLyjAvjNsb1dI6N05P
        mFAIHlHG73sEypPgGwnhfpn0zzH7jzddcK4Q7kqfKNMI4a9K+MwBDgbdeF04MBWsFYYdQvhbLlBvfhKT
        f+vMtLfG7C0JJXxKGY67WnvCmPAFGRs7z42boul5AzHBfdK6TjdQtzPGk8oos5F/5Y7sfVvPhg+lp+1h
        0yIsxARPmtaN78WEl8eEX+SNclxUhne0glUrNrN9zfMGlPAuZTzaQ99FYfwuDv3ruoLvq5bWaQSvZCfL
        GXUYLwrj240Qxtu2lkSN4FpdWfKZH9jb9RQ1Cq62f9sVOlxUxn3KQXnJ0PO8QxU/jBm1h74v7ZniEG9K
        Hdg/quzvXO709k0Y3u08ucGqWgheX862H4XgxbR47SqU8D1X0EXC2VmGizqDz0xPr0kYH9eO360gNe0b
        jWppozB+1kOQEb5MCLa0C64NoeGrhOGrvH6lhK81GiIvnggmrDLzgvTkvwvDA+5wsU4nhG/m9AUoBD/F
        HFzWN4H0XQn2vF8eXN8Z3FAPYasl59oUYjuB+sTImDB+nhfgYQ39STf4fmu1DHtz+oIUgiM1KkWtwcFw
        sOujVT3hrnaL7UQc+hcL5W+sKIXhw0OVjaW0iwnBc47gqIQ45QY32PKRzv8eTguRYM9SS5YouEEZjv37
        EffbzbjBDdZyxZYQ12EB2qS0bWrJqRVazPDWkojwZbuZrsgZtDJ0iY1g12khEtTicMTvclwn2CKE32YJ
        7G5PORfZ1HtMCH7MOV4BrQ3XCe92+4onk5Nn2PolDAvWXnuOzAwzo6Nnx4Q3SrojwqfKeMxWMpsXWVs+
        2WrfKRdbW1W6Hf0shM/33Y7my4PrleFZIfhAaWjU/e5ivlw+y3S2FySMtynjvcrwsFiLJv/RhPBB2ws1
        hK2WcBLBFf1qawlplwvxaQlxe786OOU4PBWsjSO85mBlQ8n99r/BisSdAas4FfgHpdEUZpwUX7sAAAAA
        SUVORK5CYII=
</value>
  </data>
</root>
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,509 @@
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    partial class CameraForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CameraForm));
            uiComboBoxBrand = new ComboBox();
            uiRadioButtonSoftTrigger = new RadioButton();
            uiRadioButtonHardTrigger = new RadioButton();
            uiGroupBoxImage = new GroupBox();
            uiGroupBoxCameraParams = new GroupBox();
            btnSetting = new Button();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel3 = new TableLayoutPanel();
            uiMarkLabel1 = new Label();
            tableLayoutPanel1 = new TableLayoutPanel();
            uiButtonGrabOnce = new Button();
            uiButtonStartSoftGrab = new Button();
            uiButtonCloseSoftGrab = new Button();
            uiButtonStartHardGrab = new Button();
            tableLayoutPanel4 = new TableLayoutPanel();
            uiMarkLabel2 = new Label();
            uiTextBoxExp = new TextBox();
            tableLayoutPanel5 = new TableLayoutPanel();
            uiMarkLabel3 = new Label();
            uiTextBoxGain = new TextBox();
            tableLayoutPanel6 = new TableLayoutPanel();
            uiMarkLabel4 = new Label();
            uiTextBoxGrabTime = new TextBox();
            uiSplitContainer1 = new SplitContainer();
            themeForm1 = new ReaLTaiizor.Forms.ThemeForm();
            controlBox1 = new ReaLTaiizor.Controls.ControlBox();
            uiGroupBoxCameraParams.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            tableLayoutPanel3.SuspendLayout();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel4.SuspendLayout();
            tableLayoutPanel5.SuspendLayout();
            tableLayoutPanel6.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)uiSplitContainer1).BeginInit();
            uiSplitContainer1.Panel1.SuspendLayout();
            uiSplitContainer1.Panel2.SuspendLayout();
            uiSplitContainer1.SuspendLayout();
            themeForm1.SuspendLayout();
            SuspendLayout();
            //
            // uiComboBoxBrand
            //
            uiComboBoxBrand.Dock = DockStyle.Fill;
            uiComboBoxBrand.Enabled = false;
            uiComboBoxBrand.Font = new Font("宋体", 12F);
            uiComboBoxBrand.Location = new Point(104, 5);
            uiComboBoxBrand.Margin = new Padding(4, 5, 4, 5);
            uiComboBoxBrand.MinimumSize = new Size(63, 0);
            uiComboBoxBrand.Name = "uiComboBoxBrand";
            uiComboBoxBrand.Size = new Size(260, 24);
            uiComboBoxBrand.TabIndex = 24;
            uiComboBoxBrand.SelectedIndexChanged += cob_Brand_SelectedIndexChanged;
            //
            // uiRadioButtonSoftTrigger
            //
            uiRadioButtonSoftTrigger.Dock = DockStyle.Fill;
            uiRadioButtonSoftTrigger.Font = new Font("宋体", 12F);
            uiRadioButtonSoftTrigger.Location = new Point(3, 55);
            uiRadioButtonSoftTrigger.MinimumSize = new Size(1, 1);
            uiRadioButtonSoftTrigger.Name = "uiRadioButtonSoftTrigger";
            uiRadioButtonSoftTrigger.Size = new Size(368, 46);
            uiRadioButtonSoftTrigger.TabIndex = 25;
            uiRadioButtonSoftTrigger.Text = "软触发";
            uiRadioButtonSoftTrigger.CheckedChanged += uiRadioButtonSoftTrigger_CheckedChanged;
            //
            // uiRadioButtonHardTrigger
            //
            uiRadioButtonHardTrigger.Dock = DockStyle.Fill;
            uiRadioButtonHardTrigger.Font = new Font("宋体", 12F);
            uiRadioButtonHardTrigger.Location = new Point(3, 159);
            uiRadioButtonHardTrigger.MinimumSize = new Size(1, 1);
            uiRadioButtonHardTrigger.Name = "uiRadioButtonHardTrigger";
            uiRadioButtonHardTrigger.Size = new Size(368, 46);
            uiRadioButtonHardTrigger.TabIndex = 26;
            uiRadioButtonHardTrigger.Text = "硬触发";
            //
            // uiGroupBoxImage
            //
            uiGroupBoxImage.Dock = DockStyle.Fill;
            uiGroupBoxImage.Font = new Font("宋体", 12F);
            uiGroupBoxImage.ForeColor = SystemColors.Control;
            uiGroupBoxImage.Location = new Point(0, 0);
            uiGroupBoxImage.Margin = new Padding(4, 5, 4, 5);
            uiGroupBoxImage.MinimumSize = new Size(1, 1);
            uiGroupBoxImage.Name = "uiGroupBoxImage";
            uiGroupBoxImage.Padding = new Padding(0, 32, 0, 0);
            uiGroupBoxImage.Size = new Size(495, 521);
            uiGroupBoxImage.TabIndex = 17;
            uiGroupBoxImage.TabStop = false;
            uiGroupBoxImage.Text = "实时采集";
            //
            // uiGroupBoxCameraParams
            //
            uiGroupBoxCameraParams.Controls.Add(btnSetting);
            uiGroupBoxCameraParams.Controls.Add(tableLayoutPanel2);
            uiGroupBoxCameraParams.Dock = DockStyle.Fill;
            uiGroupBoxCameraParams.Font = new Font("宋体", 12F);
            uiGroupBoxCameraParams.ForeColor = SystemColors.Control;
            uiGroupBoxCameraParams.Location = new Point(0, 0);
            uiGroupBoxCameraParams.Margin = new Padding(4, 5, 4, 5);
            uiGroupBoxCameraParams.MinimumSize = new Size(1, 1);
            uiGroupBoxCameraParams.Name = "uiGroupBoxCameraParams";
            uiGroupBoxCameraParams.Padding = new Padding(0, 32, 0, 0);
            uiGroupBoxCameraParams.Size = new Size(374, 521);
            uiGroupBoxCameraParams.TabIndex = 18;
            uiGroupBoxCameraParams.TabStop = false;
            uiGroupBoxCameraParams.Text = "相机参数";
            //
            // btnSetting
            //
            btnSetting.Location = new Point(3, 18);
            btnSetting.Name = "btnSetting";
            btnSetting.Size = new Size(97, 29);
            btnSetting.TabIndex = 18;
            btnSetting.Text = "参数设置";
            btnSetting.UseVisualStyleBackColor = true;
            btnSetting.Visible = false;
            btnSetting.Click += btn_Setting_Click;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 1;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel2.Controls.Add(uiRadioButtonHardTrigger, 0, 3);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel3, 0, 0);
            tableLayoutPanel2.Controls.Add(uiRadioButtonSoftTrigger, 0, 1);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel1, 0, 2);
            tableLayoutPanel2.Controls.Add(uiButtonStartHardGrab, 0, 4);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel4, 0, 5);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel5, 0, 6);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel6, 0, 7);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(0, 51);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 9;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 10F));
            tableLayoutPanel2.Size = new Size(374, 470);
            tableLayoutPanel2.TabIndex = 17;
            //
            // tableLayoutPanel3
            //
            tableLayoutPanel3.ColumnCount = 2;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Controls.Add(uiComboBoxBrand, 1, 0);
            tableLayoutPanel3.Controls.Add(uiMarkLabel1, 0, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 3);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 1;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Size = new Size(368, 46);
            tableLayoutPanel3.TabIndex = 0;
            //
            // uiMarkLabel1
            //
            uiMarkLabel1.Dock = DockStyle.Fill;
            uiMarkLabel1.Font = new Font("宋体", 12F);
            uiMarkLabel1.ForeColor = SystemColors.Control;
            uiMarkLabel1.Location = new Point(3, 0);
            uiMarkLabel1.Name = "uiMarkLabel1";
            uiMarkLabel1.Padding = new Padding(5, 0, 0, 0);
            uiMarkLabel1.Size = new Size(94, 46);
            uiMarkLabel1.TabIndex = 25;
            uiMarkLabel1.Text = "品牌";
            uiMarkLabel1.TextAlign = ContentAlignment.MiddleLeft;
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 3;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel1.Controls.Add(uiButtonGrabOnce, 0, 0);
            tableLayoutPanel1.Controls.Add(uiButtonStartSoftGrab, 1, 0);
            tableLayoutPanel1.Controls.Add(uiButtonCloseSoftGrab, 2, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(3, 107);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 1;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(368, 46);
            tableLayoutPanel1.TabIndex = 30;
            //
            // uiButtonGrabOnce
            //
            uiButtonGrabOnce.Dock = DockStyle.Fill;
            uiButtonGrabOnce.Font = new Font("宋体", 12F);
            uiButtonGrabOnce.Location = new Point(3, 3);
            uiButtonGrabOnce.MinimumSize = new Size(1, 1);
            uiButtonGrabOnce.Name = "uiButtonGrabOnce";
            uiButtonGrabOnce.Size = new Size(116, 40);
            uiButtonGrabOnce.TabIndex = 31;
            uiButtonGrabOnce.Text = "单张采集";
            uiButtonGrabOnce.Click += uiButtonGrabOnce_Click;
            //
            // uiButtonStartSoftGrab
            //
            uiButtonStartSoftGrab.Dock = DockStyle.Fill;
            uiButtonStartSoftGrab.Font = new Font("宋体", 12F);
            uiButtonStartSoftGrab.Location = new Point(125, 3);
            uiButtonStartSoftGrab.MinimumSize = new Size(1, 1);
            uiButtonStartSoftGrab.Name = "uiButtonStartSoftGrab";
            uiButtonStartSoftGrab.Size = new Size(116, 40);
            uiButtonStartSoftGrab.TabIndex = 31;
            uiButtonStartSoftGrab.Text = "连续采集";
            uiButtonStartSoftGrab.Click += uiButtonStartSoftGrab_Click;
            //
            // uiButtonCloseSoftGrab
            //
            uiButtonCloseSoftGrab.Dock = DockStyle.Fill;
            uiButtonCloseSoftGrab.Font = new Font("宋体", 12F);
            uiButtonCloseSoftGrab.Location = new Point(247, 3);
            uiButtonCloseSoftGrab.MinimumSize = new Size(1, 1);
            uiButtonCloseSoftGrab.Name = "uiButtonCloseSoftGrab";
            uiButtonCloseSoftGrab.Size = new Size(118, 40);
            uiButtonCloseSoftGrab.TabIndex = 31;
            uiButtonCloseSoftGrab.Text = "关闭采集";
            uiButtonCloseSoftGrab.Click += uiButtonCloseSoftGrab_Click;
            //
            // uiButtonStartHardGrab
            //
            uiButtonStartHardGrab.Dock = DockStyle.Fill;
            uiButtonStartHardGrab.Font = new Font("宋体", 12F);
            uiButtonStartHardGrab.Location = new Point(3, 211);
            uiButtonStartHardGrab.MinimumSize = new Size(1, 1);
            uiButtonStartHardGrab.Name = "uiButtonStartHardGrab";
            uiButtonStartHardGrab.Size = new Size(368, 46);
            uiButtonStartHardGrab.TabIndex = 27;
            uiButtonStartHardGrab.Text = "等待硬件触发";
            uiButtonStartHardGrab.Click += uiButtonStartHardGrab_Click;
            //
            // tableLayoutPanel4
            //
            tableLayoutPanel4.ColumnCount = 2;
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Controls.Add(uiMarkLabel2, 0, 0);
            tableLayoutPanel4.Controls.Add(uiTextBoxExp, 1, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(3, 263);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
            tableLayoutPanel4.RowCount = 1;
            tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Size = new Size(368, 46);
            tableLayoutPanel4.TabIndex = 28;
            //
            // uiMarkLabel2
            //
            uiMarkLabel2.Dock = DockStyle.Fill;
            uiMarkLabel2.Font = new Font("宋体", 12F);
            uiMarkLabel2.ForeColor = SystemColors.Control;
            uiMarkLabel2.Location = new Point(3, 0);
            uiMarkLabel2.Name = "uiMarkLabel2";
            uiMarkLabel2.Padding = new Padding(5, 0, 0, 0);
            uiMarkLabel2.Size = new Size(94, 46);
            uiMarkLabel2.TabIndex = 31;
            uiMarkLabel2.Text = "曝光(us)";
            uiMarkLabel2.TextAlign = ContentAlignment.MiddleLeft;
            //
            // uiTextBoxExp
            //
            uiTextBoxExp.Dock = DockStyle.Fill;
            uiTextBoxExp.Font = new Font("宋体", 12F);
            uiTextBoxExp.Location = new Point(104, 5);
            uiTextBoxExp.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxExp.MinimumSize = new Size(1, 16);
            uiTextBoxExp.Name = "uiTextBoxExp";
            uiTextBoxExp.Size = new Size(260, 26);
            uiTextBoxExp.TabIndex = 31;
            uiTextBoxExp.Text = "1000";
            uiTextBoxExp.TextChanged += uiTextBoxExp_TextChanged;
            //
            // tableLayoutPanel5
            //
            tableLayoutPanel5.ColumnCount = 2;
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel5.Controls.Add(uiMarkLabel3, 0, 0);
            tableLayoutPanel5.Controls.Add(uiTextBoxGain, 1, 0);
            tableLayoutPanel5.Dock = DockStyle.Fill;
            tableLayoutPanel5.Location = new Point(3, 315);
            tableLayoutPanel5.Name = "tableLayoutPanel5";
            tableLayoutPanel5.RowCount = 1;
            tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel5.Size = new Size(368, 46);
            tableLayoutPanel5.TabIndex = 29;
            //
            // uiMarkLabel3
            //
            uiMarkLabel3.Dock = DockStyle.Fill;
            uiMarkLabel3.Font = new Font("宋体", 12F);
            uiMarkLabel3.ForeColor = SystemColors.Control;
            uiMarkLabel3.Location = new Point(3, 0);
            uiMarkLabel3.Name = "uiMarkLabel3";
            uiMarkLabel3.Padding = new Padding(5, 0, 0, 0);
            uiMarkLabel3.Size = new Size(94, 46);
            uiMarkLabel3.TabIndex = 31;
            uiMarkLabel3.Text = "增益";
            uiMarkLabel3.TextAlign = ContentAlignment.MiddleLeft;
            //
            // uiTextBoxGain
            //
            uiTextBoxGain.Dock = DockStyle.Fill;
            uiTextBoxGain.Font = new Font("宋体", 12F);
            uiTextBoxGain.Location = new Point(104, 5);
            uiTextBoxGain.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxGain.MinimumSize = new Size(1, 16);
            uiTextBoxGain.Name = "uiTextBoxGain";
            uiTextBoxGain.Size = new Size(260, 26);
            uiTextBoxGain.TabIndex = 32;
            uiTextBoxGain.Text = "1";
            uiTextBoxGain.TextChanged += uiTextBoxGain_TextChanged;
            //
            // tableLayoutPanel6
            //
            tableLayoutPanel6.ColumnCount = 2;
            tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100F));
            tableLayoutPanel6.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel6.Controls.Add(uiMarkLabel4, 0, 0);
            tableLayoutPanel6.Controls.Add(uiTextBoxGrabTime, 1, 0);
            tableLayoutPanel6.Dock = DockStyle.Fill;
            tableLayoutPanel6.Location = new Point(3, 367);
            tableLayoutPanel6.Name = "tableLayoutPanel6";
            tableLayoutPanel6.RowCount = 1;
            tableLayoutPanel6.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel6.Size = new Size(368, 46);
            tableLayoutPanel6.TabIndex = 31;
            //
            // uiMarkLabel4
            //
            uiMarkLabel4.Dock = DockStyle.Fill;
            uiMarkLabel4.Font = new Font("宋体", 12F);
            uiMarkLabel4.ForeColor = SystemColors.Control;
            uiMarkLabel4.Location = new Point(3, 0);
            uiMarkLabel4.Name = "uiMarkLabel4";
            uiMarkLabel4.Padding = new Padding(5, 0, 0, 0);
            uiMarkLabel4.Size = new Size(94, 46);
            uiMarkLabel4.TabIndex = 31;
            uiMarkLabel4.Text = "耗时(ms)";
            uiMarkLabel4.TextAlign = ContentAlignment.MiddleLeft;
            //
            // uiTextBoxGrabTime
            //
            uiTextBoxGrabTime.Dock = DockStyle.Fill;
            uiTextBoxGrabTime.Enabled = false;
            uiTextBoxGrabTime.Font = new Font("宋体", 12F);
            uiTextBoxGrabTime.Location = new Point(104, 5);
            uiTextBoxGrabTime.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxGrabTime.MinimumSize = new Size(1, 16);
            uiTextBoxGrabTime.Name = "uiTextBoxGrabTime";
            uiTextBoxGrabTime.Size = new Size(260, 26);
            uiTextBoxGrabTime.TabIndex = 31;
            //
            // uiSplitContainer1
            //
            uiSplitContainer1.Dock = DockStyle.Fill;
            uiSplitContainer1.ForeColor = SystemColors.Control;
            uiSplitContainer1.Location = new Point(10, 70);
            uiSplitContainer1.MinimumSize = new Size(20, 20);
            uiSplitContainer1.Name = "uiSplitContainer1";
            //
            // uiSplitContainer1.Panel1
            //
            uiSplitContainer1.Panel1.Controls.Add(uiGroupBoxCameraParams);
            //
            // uiSplitContainer1.Panel2
            //
            uiSplitContainer1.Panel2.Controls.Add(uiGroupBoxImage);
            uiSplitContainer1.Size = new Size(880, 521);
            uiSplitContainer1.SplitterDistance = 374;
            uiSplitContainer1.SplitterWidth = 11;
            uiSplitContainer1.TabIndex = 20;
            //
            // themeForm1
            //
            themeForm1.BackColor = Color.FromArgb(32, 41, 50);
            themeForm1.Controls.Add(controlBox1);
            themeForm1.Controls.Add(uiSplitContainer1);
            themeForm1.Dock = DockStyle.Fill;
            themeForm1.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 0);
            themeForm1.Image = (Image)resources.GetObject("themeForm1.Image");
            themeForm1.Location = new Point(0, 0);
            themeForm1.Name = "themeForm1";
            themeForm1.Padding = new Padding(10, 70, 10, 9);
            themeForm1.RoundCorners = true;
            themeForm1.Sizable = true;
            themeForm1.Size = new Size(900, 600);
            themeForm1.SmartBounds = true;
            themeForm1.StartPosition = FormStartPosition.WindowsDefaultLocation;
            themeForm1.TabIndex = 21;
            themeForm1.Text = "相机设置";
            //
            // controlBox1
            //
            controlBox1.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            controlBox1.BackColor = Color.FromArgb(32, 34, 37);
            controlBox1.CloseHoverColor = Color.FromArgb(230, 17, 35);
            controlBox1.DefaultLocation = true;
            controlBox1.EnableHoverHighlight = true;
            controlBox1.EnableMaximizeButton = true;
            controlBox1.EnableMinimizeButton = true;
            controlBox1.ForeColor = Color.FromArgb(155, 155, 155);
            controlBox1.Location = new Point(800, 18);
            controlBox1.MaximizeHoverColor = Color.FromArgb(74, 74, 74);
            controlBox1.MinimizeHoverColor = Color.FromArgb(63, 63, 65);
            controlBox1.Name = "controlBox1";
            controlBox1.Size = new Size(90, 25);
            controlBox1.TabIndex = 21;
            controlBox1.Text = "controlBox1";
            //
            // CameraForm
            //
            AutoScaleMode = AutoScaleMode.None;
            ClientSize = new Size(900, 600);
            Controls.Add(themeForm1);
            FormBorderStyle = FormBorderStyle.None;
            MinimumSize = new Size(261, 61);
            Name = "CameraForm";
            Text = "相机设置";
            TransparencyKey = Color.Fuchsia;
            FormClosing += CameraForm_FormClosing;
            uiGroupBoxCameraParams.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            tableLayoutPanel3.ResumeLayout(false);
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel4.ResumeLayout(false);
            tableLayoutPanel4.PerformLayout();
            tableLayoutPanel5.ResumeLayout(false);
            tableLayoutPanel5.PerformLayout();
            tableLayoutPanel6.ResumeLayout(false);
            tableLayoutPanel6.PerformLayout();
            uiSplitContainer1.Panel1.ResumeLayout(false);
            uiSplitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)uiSplitContainer1).EndInit();
            uiSplitContainer1.ResumeLayout(false);
            themeForm1.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private RadioButton uiRadioButtonHardTrigger;
        private RadioButton uiRadioButtonSoftTrigger;
        private ComboBox uiComboBoxBrand;
        private GroupBox uiGroupBoxImage;
        private GroupBox uiGroupBoxCameraParams;
        private SplitContainer uiSplitContainer1;
        private Button uiButtonStartHardGrab;
        private TableLayoutPanel tableLayoutPanel2;
        private TableLayoutPanel tableLayoutPanel5;
        private TableLayoutPanel tableLayoutPanel3;
        private TableLayoutPanel tableLayoutPanel4;
        private Label uiMarkLabel1;
        private TableLayoutPanel tableLayoutPanel1;
        private Button uiButtonGrabOnce;
        private Button uiButtonStartSoftGrab;
        private Button uiButtonCloseSoftGrab;
        private Label uiMarkLabel2;
        private TextBox uiTextBoxExp;
        private Label uiMarkLabel3;
        private TextBox uiTextBoxGain;
        private TableLayoutPanel tableLayoutPanel6;
        private Label uiMarkLabel4;
        private TextBox uiTextBoxGrabTime;
        private Button btnSetting;
        private ReaLTaiizor.Forms.ThemeForm themeForm1;
        private ReaLTaiizor.Controls.ControlBox controlBox1;
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,272 @@
using LB_VisionControl;
using LB_VisionProcesses.Cameras;
using ReaLTaiizor.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using static System.Net.Mime.MediaTypeNames;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    public partial class CameraForm : Form
    {
        BaseCamera camera { get; set; }
        UserPictureBox onlinePictureBox { get; set; }
        public CameraForm()
        {
            InitializeComponent();
        }
        public CameraForm(BaseCamera camera)
        {
            InitializeComponent();
            // ä½¿ç”¨ LINQ èŽ·å–æ‰€æœ‰æžšä¸¾å€¼å¹¶æ‰“å°
            var brands = Enum.GetValues(typeof(CameraBrand)).Cast<CameraBrand>();
            foreach (var brand in brands)
                uiComboBoxBrand.Items.Add(brand.ToString());
            if (camera == null)
                return;
            this.camera = camera;
            this.Text = camera.SN;
            //设置品牌
            onlinePictureBox = new UserPictureBox(uiGroupBoxImage);
            this.uiGroupBoxImage.Controls.Clear();
            this.uiGroupBoxImage.Controls.Add(onlinePictureBox);
            onlinePictureBox.Dock = DockStyle.Fill;
            //设置触发
            camera.GetTriggerMode(out TriggerMode triggerMode, out TriggerSource triggerSource);
            if (triggerSource == TriggerSource.Software)
                uiRadioButtonSoftTrigger.Checked = true;
            else
                uiRadioButtonHardTrigger.Checked = true;
            uiButtonGrabOnce.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonStartSoftGrab.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonCloseSoftGrab.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonStartHardGrab.Enabled = !uiRadioButtonSoftTrigger.Checked;
            //设置曝光和增益
            camera.GetExpouseTime(out double exp);
            uiTextBoxExp.Text = exp.ToString();
            camera.GetGain(out double gain);
            uiTextBoxGain.Text = gain.ToString();
            //加载回调函数
            Subscribe();
        }
        private void CameraForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (camera == null)
                return;
            camera.StopGrabbing();
            if (uiRadioButtonSoftTrigger.Checked)
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
            else
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
            camera.StartGrabbing();
            Unsubscribe();
        }
        public void Unsubscribe()
        {
            try
            {
                if (camera == null)
                    return;
                //取消回调函数
                camera.ImageGrabbed -= GetImageBllComplete;
            }
            catch (Exception ex)
            {
                // è®°å½•错误信息
                Debug.WriteLine($"错误: {ex.Message}");
            }
        }
        public void Subscribe()
        {
            try
            {
                if (camera == null)
                    return;
                //取消回调函数
                camera.ImageGrabbed -= GetImageBllComplete;
                //加载回调函数
                camera.ImageGrabbed += GetImageBllComplete;
            }
            catch (Exception ex)
            {
                // è®°å½•错误信息
                Debug.WriteLine($"错误: {ex.Message}");
            }
        }
        private void uiRadioButtonSoftTrigger_CheckedChanged(object sender, EventArgs e)
        {
            uiButtonGrabOnce.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonStartSoftGrab.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonCloseSoftGrab.Enabled = uiRadioButtonSoftTrigger.Checked;
            uiButtonStartHardGrab.Enabled = !uiRadioButtonSoftTrigger.Checked;
            if (camera == null)
                return;
            if (uiRadioButtonSoftTrigger.Checked)
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
            else
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Line0);
        }
        private void uiButtonGrabOnce_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            Task.Factory.StartNew(() =>
            {
                DateTime startTime = DateTime.Now; // å½“前时间
                camera.GetImageWithSoftTrigger(out Bitmap bitmap);
                this.BeginInvoke(new Action(() =>
                {
                    if (bitmap != null)
                        this.uiTextBoxGrabTime.Text = (DateTime.Now - startTime).TotalMilliseconds.ToString();
                    else
                        this.uiTextBoxGrabTime.Text = "-1ms";
                }));
            });
        }
        private void uiButtonStartSoftGrab_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            Task.Factory.StartNew(() =>
            {
                camera.StopGrabbing();
                camera.StartWith_SoftTriggerModel();
            });
        }
        private void uiButtonCloseSoftGrab_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            Task.Factory.StartNew(() =>
            {
                camera.StopGrabbing();
                camera.SetTriggerMode(TriggerMode.On, TriggerSource.Software);
                camera.StartGrabbing();
            });
        }
        private void uiButtonStartHardGrab_Click(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            Task.Factory.StartNew(() =>
            {
                camera.StopGrabbing();
                camera.StartWith_HardTriggerModel();
            });
        }
        /// <summary>
        /// ç›¸æœºå›žè°ƒè¿è¡Œ
        /// </summary>
        /// <param name="CCDName"></param>
        /// <param name="image"></param>
        private void GetImageBllComplete(object sender, CameraEventArgs e)
        {
            if (e.Bitmap == null)
                return;
            lock (e.Bitmap)
            {
                if (this.InvokeRequired) // æ£€æŸ¥æ˜¯å¦éœ€è¦åœ¨UI线程上调用
                {
                    this.Invoke(new Action(() =>
                    {
                        onlinePictureBox.Image = e.Bitmap;
                    })); // é€’归调用自身,但这次在UI线程上
                }
                else
                {
                    onlinePictureBox.Image = e.Bitmap;
                }
            }
        }
        private ulong ImageWidth;
        private ulong ImageHeight;
        private Pen pen = new Pen(Color.Blue, 3f);
        private System.Drawing.Point[] stPointList = new System.Drawing.Point[4];
        private void pictureBox_Paint(object sender, PaintEventArgs e)
        {
        }
        private void uiTextBoxExp_TextChanged(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            double exp = 1000;
            if (double.TryParse(uiTextBoxExp.Text.ToString(), out exp))
                camera.SetExpouseTime(exp);
        }
        private void uiTextBoxGain_TextChanged(object sender, EventArgs e)
        {
            if (camera == null)
                return;
            double gain = 10;
            if (double.TryParse(uiTextBoxGain.Text.ToString(), out gain))
                camera.SetGain(gain);
        }
        private void cob_Brand_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (uiComboBoxBrand.Text == "MindCamera")
                btnSetting.Visible = true;
            else
                btnSetting.Visible = false;
        }
        private void btn_Setting_Click(object sender, EventArgs e)
        {
        }
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CameraForm.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
<?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>
  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <data name="themeForm1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
        vgAADr4B6kKxwAAAA+JJREFUWEftVkuIHGUQbt34iMEoq2S2q3p3yTJsuqpnJ+L6WBRdwaigohfFgEou
        BkVBUPCBCEG8BXNQ48GLeImCehIJxMsqhsSZruod46K4HtSIGjU+4iOr0c1I9fSsM3/PLNtCPO0H36m/
        evz/X11VnreKVRTAHPOZumkY6lFwqURws3BwZ8ywTQnuiCP/+iTCzY1qaUPzdm/Atf3PaHre6XPsjyQM
        2xLGV4XwIyX4QRj+UMK/lPFvJTyhBMeV8IgQvmRJuH4Ko+l5p9UjGBbCJ5RxTgj+VMZmXxKcSAjekHE/
        NNs5DgaTKLinEQYVO4Trf1mkV81wixLUslPmA3bzF2XcKeP+hWY/u3n0fCXcrQwLyjAvjNsb1dI6N05P
        mFAIHlHG73sEypPgGwnhfpn0zzH7jzddcK4Q7kqfKNMI4a9K+MwBDgbdeF04MBWsFYYdQvhbLlBvfhKT
        f+vMtLfG7C0JJXxKGY67WnvCmPAFGRs7z42boul5AzHBfdK6TjdQtzPGk8oos5F/5Y7sfVvPhg+lp+1h
        0yIsxARPmtaN78WEl8eEX+SNclxUhne0glUrNrN9zfMGlPAuZTzaQ99FYfwuDv3ruoLvq5bWaQSvZCfL
        GXUYLwrj240Qxtu2lkSN4FpdWfKZH9jb9RQ1Cq62f9sVOlxUxn3KQXnJ0PO8QxU/jBm1h74v7ZniEG9K
        Hdg/quzvXO709k0Y3u08ucGqWgheX862H4XgxbR47SqU8D1X0EXC2VmGizqDz0xPr0kYH9eO360gNe0b
        jWppozB+1kOQEb5MCLa0C64NoeGrhOGrvH6lhK81GiIvnggmrDLzgvTkvwvDA+5wsU4nhG/m9AUoBD/F
        HFzWN4H0XQn2vF8eXN8Z3FAPYasl59oUYjuB+sTImDB+nhfgYQ39STf4fmu1DHtz+oIUgiM1KkWtwcFw
        sOujVT3hrnaL7UQc+hcL5W+sKIXhw0OVjaW0iwnBc47gqIQ45QY32PKRzv8eTguRYM9SS5YouEEZjv37
        EffbzbjBDdZyxZYQ12EB2qS0bWrJqRVazPDWkojwZbuZrsgZtDJ0iY1g12khEtTicMTvclwn2CKE32YJ
        7G5PORfZ1HtMCH7MOV4BrQ3XCe92+4onk5Nn2PolDAvWXnuOzAwzo6Nnx4Q3SrojwqfKeMxWMpsXWVs+
        2WrfKRdbW1W6Hf0shM/33Y7my4PrleFZIfhAaWjU/e5ivlw+y3S2FySMtynjvcrwsFiLJv/RhPBB2ws1
        hK2WcBLBFf1qawlplwvxaQlxe786OOU4PBWsjSO85mBlQ8n99r/BisSdAas4FfgHpdEUZpwUX7sAAAAA
        SUVORK5CYII=
</value>
  </data>
</root>
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,153 @@

using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    partial class CamerasEditPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            uiButton1 = new HopeButton();
            uiButton2 = new LostButton();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // uiButton1
            //
            uiButton1.BorderColor = Color.FromArgb(220, 223, 230);
            uiButton1.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            uiButton1.Cursor = Cursors.Hand;
            uiButton1.DangerColor = Color.FromArgb(245, 108, 108);
            uiButton1.DefaultColor = Color.FromArgb(255, 255, 255);
            uiButton1.Dock = DockStyle.Fill;
            uiButton1.Font = new Font("宋体", 12F);
            uiButton1.HoverTextColor = Color.FromArgb(48, 49, 51);
            uiButton1.InfoColor = Color.FromArgb(144, 147, 153);
            uiButton1.Location = new Point(503, 3);
            uiButton1.MinimumSize = new Size(1, 1);
            uiButton1.Name = "uiButton1";
            uiButton1.PrimaryColor = Color.FromArgb(64, 158, 255);
            uiButton1.Size = new Size(95, 38);
            uiButton1.SuccessColor = Color.FromArgb(103, 194, 58);
            uiButton1.TabIndex = 11;
            uiButton1.Text = "增加";
            uiButton1.TextColor = Color.White;
            uiButton1.WarningColor = Color.FromArgb(230, 162, 60);
            uiButton1.Click += uiButton1_Click;
            //
            // uiButton2
            //
            uiButton2.BackColor = Color.FromArgb(39, 41, 60);
            uiButton2.Cursor = Cursors.Hand;
            uiButton2.Dock = DockStyle.Fill;
            uiButton2.Font = new Font("宋体", 12F);
            uiButton2.ForeColor = Color.White;
            uiButton2.HoverColor = Color.DodgerBlue;
            uiButton2.Image = null;
            uiButton2.Location = new Point(403, 3);
            uiButton2.MinimumSize = new Size(1, 1);
            uiButton2.Name = "uiButton2";
            uiButton2.Size = new Size(94, 38);
            uiButton2.TabIndex = 12;
            uiButton2.Text = "清除";
            uiButton2.Click += uiButton2_Click;
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(599, 293);
            uiFlowLayoutPanel1.TabIndex = 10;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(607, 353);
            tableLayoutPanel1.TabIndex = 13;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.Controls.Add(uiButton1, 5, 0);
            tableLayoutPanel2.Controls.Add(uiButton2, 4, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 306);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(601, 44);
            tableLayoutPanel2.TabIndex = 11;
            //
            // CamerasEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(tableLayoutPanel1);
            Name = "CamerasEditPage";
            Size = new Size(607, 353);
            Paint += CamerasEditPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton uiButton1;
        private ReaLTaiizor.Controls.LostButton uiButton2;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,180 @@

using LB_VisionControl;
using LB_VisionProcesses.Cameras;
using OpenCvSharp.Flann;
using System;
using System.Collections.Concurrent;
using System.Windows.Forms;
using System.Xml.Linq;
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    public partial class CamerasEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        public CamerasEditPage()
        {
            InitializeComponent();
            Name = "CamerasEditPage";
            Text = "相机设置";
            //this.Font = new Font("Microsoft YaHei UI", 16F, FontStyle.Regular, GraphicsUnit.Point, 0);
        }
        private void CamerasEditPage_Paint(object sender, PaintEventArgs e)
        {
            uiFlowLayoutPanel1.Controls.Clear();
            if (GlobalVar.dicCameras.Count <= 0)
                return;
            foreach (var item in GlobalVar.dicCameras)
            {
                string CameraSN = item.Key;
                string CameraBrand = item.Value.Brand.ToString();
                if (string.IsNullOrEmpty(CameraSN) || string.IsNullOrEmpty(CameraBrand))
                    return;
                UserItem flow = new UserItem(new string[] { "测试", "刷新", "移除" });
                flow.Name = CameraSN;
                flow.Text = $"[{CameraBrand}]";
                if (item.Value.isGrabbing)
                    flow.state = State.Pass;
                else
                    flow.state |= State.Error;
                LoadFlowEvent(flow);
                uiFlowLayoutPanel1.Controls.Add(flow);
            }
        }
        private void uiButton1_Click(object sender, System.EventArgs e)
        {
            CreateCameraForm createCameraForm = new CreateCameraForm();
            createCameraForm.ShowDialog();
            if (createCameraForm.bCreate)
            {
                BaseCamera camera = createCameraForm.camera;
                if (GlobalVar.dicCameras.ContainsKey(camera.SN))
                {
                    MessageBox.Show($"相机[{camera.SN}]已存在!", "异常");
                    return;
                }
                string CameraSN = camera.SN;//"127.0.0.1"
                string CameraBrand = camera.Brand.ToString();//"1111"
                if (string.IsNullOrEmpty(CameraSN) || string.IsNullOrEmpty(CameraBrand))
                    return;
                GlobalVar.dicCameras.TryAdd(CameraSN, camera);
                LogInfo?.Invoke(string.Format("添加相机[{0}][{1}]成功", CameraBrand, CameraSN), LogInfoType.PASS);
            }
            this.Invalidate();
        }
        private void uiButton2_Click(object sender, System.EventArgs e)
        {
            //清除用Clear方法
            uiFlowLayoutPanel1.Controls.Clear();
            foreach (var camera in GlobalVar.dicCameras.Values)
            {
                camera.CloseDevice();
            }
            GlobalVar.dicCameras.Clear();
        }
        private void LoadFlowEvent(UserItem flow)
        {
            //按键1为测试
            flow.MenuItem1ClickedEvent += TestEvent;
            //按键2为刷新
            flow.MenuItem2ClickedEvent += ReconnectEvent;
            //按键3为移除
            flow.MenuItem3ClickedEvent += DeleteEvent;
        }
        private void RemoveFlowEvent(UserItem flow)
        {
            //按键1为测试
            flow.MenuItem1ClickedEvent -= TestEvent;
            //按键2为刷新
            flow.MenuItem2ClickedEvent -= ReconnectEvent;
            //按键3为移除
            flow.MenuItem3ClickedEvent += DeleteEvent;
        }
        // æµ‹è¯•相机
        private void TestEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                if (GlobalVar.dicCameras.ContainsKey(name))
                {
                    CameraForm cameraForm = new CameraForm(GlobalVar.dicCameras[name]);
                    cameraForm.Show();
                }
            }
        }
        // ç§»é™¤ç›¸æœº
        private void DeleteEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                RemoveFlowEvent(flow);
                uiFlowLayoutPanel1.Controls.Remove(uiFlowLayoutPanel1.Controls[i]);
                if (GlobalVar.dicCameras.TryRemove(name, out BaseCamera BaseCamera))
                {
                    BaseCamera.Dispose();
                    LogInfo?.Invoke(string.Format("移除相机[{0}]", name), LogInfoType.INFO);
                }
                else
                    LogInfo?.Invoke(string.Format("移除相机[{0}]失败", name), LogInfoType.ERROR);
            }
        }
        // é‡è¿žç›¸æœº
        private void ReconnectEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                GlobalVar.dicCameras[name].CloseDevice();
                Thread.Sleep(50);
                GlobalVar.dicCameras[name].InitDevice(name, this.Handle);
                if (GlobalVar.dicCameras[name].isGrabbing)
                {
                    flow.state = State.Pass;
                    LogInfo?.Invoke(string.Format("重连相机[{0}]成功", name), LogInfoType.PASS);
                }
                else
                {
                    flow.state = State.Error;
                    LogInfo?.Invoke(string.Format("重连相机[{0}]失败", name), LogInfoType.ERROR);
                }
                flow.Refresh();
            }
        }
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CamerasEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,196 @@
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    partial class CreateCameraForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateCameraForm));
            uiLabel1 = new Label();
            uiLabel2 = new Label();
            uiButtonCancel = new Button();
            uiButtonCreate = new Button();
            uiButtonTest = new Button();
            uiComboBoxBrand = new ComboBox();
            uiComboBoxSN = new ComboBox();
            themeForm1 = new ReaLTaiizor.Forms.ThemeForm();
            controlBox1 = new ReaLTaiizor.Controls.ControlBox();
            themeForm1.SuspendLayout();
            SuspendLayout();
            //
            // uiLabel1
            //
            uiLabel1.Font = new Font("宋体", 12F);
            uiLabel1.ForeColor = SystemColors.Control;
            uiLabel1.Location = new Point(120, 97);
            uiLabel1.Name = "uiLabel1";
            uiLabel1.Size = new Size(100, 23);
            uiLabel1.TabIndex = 1;
            uiLabel1.Text = "品牌";
            //
            // uiLabel2
            //
            uiLabel2.Font = new Font("宋体", 12F);
            uiLabel2.ForeColor = SystemColors.Control;
            uiLabel2.Location = new Point(120, 163);
            uiLabel2.Name = "uiLabel2";
            uiLabel2.Size = new Size(100, 23);
            uiLabel2.TabIndex = 2;
            uiLabel2.Text = "相机SN";
            //
            // uiButtonCancel
            //
            uiButtonCancel.Font = new Font("宋体", 12F);
            uiButtonCancel.ForeColor = SystemColors.Control;
            uiButtonCancel.Location = new Point(343, 234);
            uiButtonCancel.MinimumSize = new Size(1, 1);
            uiButtonCancel.Name = "uiButtonCancel";
            uiButtonCancel.Size = new Size(100, 35);
            uiButtonCancel.TabIndex = 4;
            uiButtonCancel.Text = "取消";
            uiButtonCancel.Click += uiButtonCancel_Click;
            //
            // uiButtonCreate
            //
            uiButtonCreate.Enabled = false;
            uiButtonCreate.Font = new Font("宋体", 12F);
            uiButtonCreate.ForeColor = SystemColors.Control;
            uiButtonCreate.Location = new Point(187, 234);
            uiButtonCreate.MinimumSize = new Size(1, 1);
            uiButtonCreate.Name = "uiButtonCreate";
            uiButtonCreate.Size = new Size(100, 35);
            uiButtonCreate.TabIndex = 9;
            uiButtonCreate.Text = "创建";
            uiButtonCreate.Click += uiButtonCreate_Click;
            //
            // uiButtonTest
            //
            uiButtonTest.Font = new Font("宋体", 12F);
            uiButtonTest.ForeColor = SystemColors.Control;
            uiButtonTest.Location = new Point(31, 234);
            uiButtonTest.MinimumSize = new Size(1, 1);
            uiButtonTest.Name = "uiButtonTest";
            uiButtonTest.Size = new Size(100, 35);
            uiButtonTest.TabIndex = 10;
            uiButtonTest.Text = "测试";
            uiButtonTest.Click += uiButtonTest_Click;
            //
            // uiComboBoxBrand
            //
            uiComboBoxBrand.Font = new Font("宋体", 12F);
            uiComboBoxBrand.Location = new Point(227, 94);
            uiComboBoxBrand.Margin = new Padding(4, 5, 4, 5);
            uiComboBoxBrand.MinimumSize = new Size(63, 0);
            uiComboBoxBrand.Name = "uiComboBoxBrand";
            uiComboBoxBrand.Size = new Size(150, 24);
            uiComboBoxBrand.TabIndex = 11;
            uiComboBoxBrand.SelectedIndexChanged += uiComboBoxBrand_SelectedIndexChanged;
            uiComboBoxBrand.MouseClick += uiComboBoxBrand_MouseClick;
            //
            // uiComboBoxSN
            //
            uiComboBoxSN.Font = new Font("宋体", 12F);
            uiComboBoxSN.Location = new Point(227, 157);
            uiComboBoxSN.Margin = new Padding(4, 5, 4, 5);
            uiComboBoxSN.MinimumSize = new Size(63, 0);
            uiComboBoxSN.Name = "uiComboBoxSN";
            uiComboBoxSN.Size = new Size(150, 24);
            uiComboBoxSN.TabIndex = 12;
            uiComboBoxSN.MouseClick += uiComboBoxSN_MouseClick;
            //
            // themeForm1
            //
            themeForm1.BackColor = Color.FromArgb(32, 41, 50);
            themeForm1.Controls.Add(controlBox1);
            themeForm1.Dock = DockStyle.Fill;
            themeForm1.Font = new Font("Microsoft Sans Serif", 9F);
            themeForm1.ForeColor = SystemColors.Control;
            themeForm1.Image = (Image)resources.GetObject("themeForm1.Image");
            themeForm1.Location = new Point(0, 0);
            themeForm1.Name = "themeForm1";
            themeForm1.Padding = new Padding(10, 70, 10, 9);
            themeForm1.RoundCorners = true;
            themeForm1.Sizable = true;
            themeForm1.Size = new Size(507, 309);
            themeForm1.SmartBounds = true;
            themeForm1.StartPosition = FormStartPosition.WindowsDefaultLocation;
            themeForm1.TabIndex = 13;
            themeForm1.Text = "创建相机";
            //
            // controlBox1
            //
            controlBox1.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            controlBox1.BackColor = Color.FromArgb(32, 34, 37);
            controlBox1.CloseHoverColor = Color.FromArgb(230, 17, 35);
            controlBox1.DefaultLocation = true;
            controlBox1.EnableHoverHighlight = true;
            controlBox1.EnableMaximizeButton = true;
            controlBox1.EnableMinimizeButton = true;
            controlBox1.ForeColor = Color.FromArgb(155, 155, 155);
            controlBox1.Location = new Point(405, 12);
            controlBox1.MaximizeHoverColor = Color.FromArgb(74, 74, 74);
            controlBox1.MinimizeHoverColor = Color.FromArgb(63, 63, 65);
            controlBox1.Name = "controlBox1";
            controlBox1.Size = new Size(90, 25);
            controlBox1.TabIndex = 0;
            controlBox1.Text = "controlBox1";
            //
            // CreateCameraForm
            //
            AutoScaleMode = AutoScaleMode.None;
            ClientSize = new Size(507, 309);
            ControlBox = false;
            Controls.Add(uiComboBoxSN);
            Controls.Add(uiComboBoxBrand);
            Controls.Add(uiButtonTest);
            Controls.Add(uiButtonCreate);
            Controls.Add(uiButtonCancel);
            Controls.Add(uiLabel2);
            Controls.Add(uiLabel1);
            Controls.Add(themeForm1);
            FormBorderStyle = FormBorderStyle.None;
            MaximizeBox = false;
            MinimizeBox = false;
            MinimumSize = new Size(261, 61);
            Name = "CreateCameraForm";
            Text = "创建相机";
            TransparencyKey = Color.Fuchsia;
            themeForm1.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private Label uiLabel1;
        private Label uiLabel2;
        private Button uiButtonCancel;
        private Button uiButtonCreate;
        private Button uiButtonTest;
        private ComboBox uiComboBoxBrand;
        private ComboBox uiComboBoxSN;
        private ReaLTaiizor.Forms.ThemeForm themeForm1;
        private ReaLTaiizor.Controls.ControlBox controlBox1;
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,121 @@
using LB_VisionProcesses.Cameras;
using RJCP.IO.Ports;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace LB_SmartVision.Forms.Pages.CameraPage
{
    public partial class CreateCameraForm : Form
    {
        public BaseCamera camera { get; set; }
        public bool bCreate = false;
        public CreateCameraForm(ICamera camera = null)
        {
            InitializeComponent();
            // ç¦æ­¢ä¿®æ”¹çª—口大小
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            if (camera == null)
                //camera = new HRCamera();
            uiButtonCreate.Enabled = false;
        }
        private void uiButtonTest_Click(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            if (string.IsNullOrEmpty(uiComboBoxSN.Text))
                MessageBox.Show($"初始化相机[{uiComboBoxSN.Text}]为空!", "异常");
            if (camera == null)
            {
                MessageBox.Show("请先选择相机品牌!", "异常");
                return;
            }
            camera.CloseDevice();
            if (camera.InitDevice(uiComboBoxSN.Text, this.Handle))
            {
                uiButtonCreate.Enabled = true;
                camera.CloseDevice();
            }
            else
                MessageBox.Show($"初始化相机[{uiComboBoxSN.Text}]失败!", "异常");
        }
        private void uiButtonCreate_Click(object sender, EventArgs e)
        {
            if (camera.InitDevice(uiComboBoxSN.Text, this.Handle))
            {
                bCreate = true;
                this.Close();
            }
            else
                MessageBox.Show($"初始化相机[{uiComboBoxSN.Text}]失败!", "异常");
        }
        private void uiButtonCancel_Click(object sender, EventArgs e)
        {
            if (camera != null)
                camera.CloseDevice();
            bCreate = false;
            this.Close();
        }
        private void uiComboBoxBrand_MouseClick(object sender, MouseEventArgs e)
        {
            uiComboBoxBrand.Items.Clear();
            foreach (CameraBrand brand in Enum.GetValues(typeof(CameraBrand)))
            {
                if (brand != CameraBrand.UNSUPPORTED)
                    uiComboBoxBrand.Items.Add(brand.ToString());
            }
        }
        private void uiComboBoxBrand_SelectedIndexChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            uiComboBoxSN.Text = string.Empty;
            if (camera != null)
                camera.CloseDevice();
            Enum.TryParse<CameraBrand>(uiComboBoxBrand.Text, out CameraBrand brand);
            switch (brand)
            {
                case CameraBrand.HRCamera:
                    //camera = new HRCamera();
                    break;
                case CameraBrand.LBCamera:
                    //camera = new LBCamera();
                    break;
                default:
                    return;
            }
        }
        private void uiComboBoxSN_MouseClick(object sender, MouseEventArgs e)
        {
            uiButtonCreate.Enabled = false;
            uiComboBoxSN.Text = string.Empty;
            uiComboBoxSN.Items.Clear();
            var list = camera.GetListEnum();
            foreach (string sn in list)
                uiComboBoxSN.Items.Add(sn);
        }
    }
}
LB_SmartVision/Forms/Pages/CameraPage/CreateCameraForm.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,144 @@
<?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>
  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <data name="themeForm1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAPiSURBVFhH7VZLiBxlEG7d+IjBKKtktqt6d8kybLqqZyfi
        +lgUXcGooKIXxYBKLgZFQVDwgQhBvAVzUOPBi3iJgnoSCcTLKobEma7qHeOiuB7UiBo1PuIjq9HNSPX0
        rDN/zyzbQjztB9+pv3r8/19dVZ63ilUUwBzzmbppGOpRcKlEcLNwcGfMsE0J7ogj//okws2NamlD83Zv
        wLX9z2h63ulz7I8kDNsSxleF8CMl+EEY/lDCv5TxbyU8oQTHlfCIEL5kSbh+CqPpeafVIxgWwieUcU4I
        /lTGZl8SnEgI3pBxPzTbOQ4Gkyi4pxEGFTuE639ZpFfNcIsS1LJT5gN28xdl3Cnj/oVmP7t59Hwl3K0M
        C8owL4zbG9XSOjdOT5hQCB5Rxu97BMqT4BsJ4X6Z9M8x+483XXCuEO5KnyjTCOGvSvjMAQ4G3XhdODAV
        rBWGHUL4Wy5Qb34Sk3/rzLS3xuwtCSV8ShmOu1p7wpjwBRkbO8+Nm6LpeQMxwX3Suk43ULczxpPKKLOR
        f+WO7H1bz4YPpaftYdMiLMQET5rWje/FhJfHhF/kjXJcVIZ3tIJVKzazfc3zBpTwLmU82kPfRWH8Lg79
        67qC76uW1mkEr2Qnyxl1GC8K49uNEMbbtpZEjeBaXVnymR/Y2/UUNQqutn/bFTpcVMZ9ykF5ydDzvEMV
        P4wZtYe+L+2Z4hBvSh3YP6rs71zu9PZNGN7tPLnBqloIXl/Oth+F4MW0eO0qlPA9V9BFwtlZhos6g89M
        T69JGB/Xjt+tIDXtG41qaaMwftZDkBG+TAi2tAuuDaHhq4Thq7x+pYSvNRoiL54IJqwy84L05L8LwwPu
        cLFOJ4Rv5vQFKAQ/xRxc1jeB9F0J9rxfHlzfGdxQD2GrJefaFGI7gfrEyJgwfp4X4GEN/Uk3+H5rtQx7
        c/qCFIIjNSpFrcHBcLDro1U94a52i+1EHPoXC+VvrCiF4cNDlY2ltIsJwXOO4KiEOOUGN9jykc7/Hk4L
        kWDPUkuWKLhBGY79+xH32824wQ3WcsWWENdhAdqktG1qyakVWszw1pKI8GW7ma7IGbQydImNYNdpIRLU
        4nDE73JcJ9gihN9mCexuTzkX2dR7TAh+zDleAa0N1wnvdvuKJ5OTZ9j6JQwL1l57jswMM6OjZ8eEN0q6
        I8KnynjMVjKbF1lbPtlq3ykXW1tVuh39LITP992O5suD65XhWSH4QGlo1P3uYr5cPst0thckjLcp473K
        8LBYiyb/0YTwQdsLNYStlnASwRX9amsJaZcL8WkJcXu/OjjlODwVrI0jvOZgZUPJ/fa/wYrEnQGrOBX4
        B6XRFGacFF+7AAAAAElFTkSuQmCC
</value>
  </data>
</root>
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,239 @@
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    partial class CommunicatorForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            label3 = new Label();
            tableLayoutPanel1 = new TableLayoutPanel();
            grpReceive = new GroupBox();
            txtReceiveMsg = new TextBox();
            txtSendMsg = new TextBox();
            grpSetting = new GroupBox();
            txtIP = new TextBox();
            txtPort = new TextBox();
            lblPort = new Label();
            cmbIP = new ComboBox();
            lblIP = new Label();
            tableLayoutPanel2 = new TableLayoutPanel();
            btnRuleSend = new Button();
            btnSend = new Button();
            tableLayoutPanel1.SuspendLayout();
            grpReceive.SuspendLayout();
            grpSetting.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // label3
            //
            label3.AutoSize = true;
            label3.Dock = DockStyle.Fill;
            label3.Location = new Point(3, 100);
            label3.Name = "label3";
            label3.Size = new Size(669, 20);
            label3.TabIndex = 18;
            label3.Text = "发送信息";
            label3.TextAlign = ContentAlignment.BottomLeft;
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(grpReceive, 0, 4);
            tableLayoutPanel1.Controls.Add(txtSendMsg, 0, 2);
            tableLayoutPanel1.Controls.Add(grpSetting, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 3);
            tableLayoutPanel1.Controls.Add(label3, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(3, 64);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 5;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 40F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(675, 334);
            tableLayoutPanel1.TabIndex = 26;
            //
            // grpReceive
            //
            grpReceive.Controls.Add(txtReceiveMsg);
            grpReceive.Dock = DockStyle.Fill;
            grpReceive.Location = new Point(3, 193);
            grpReceive.Name = "grpReceive";
            grpReceive.Size = new Size(669, 138);
            grpReceive.TabIndex = 30;
            grpReceive.TabStop = false;
            grpReceive.Text = "通讯记录";
            //
            // txtReceiveMsg
            //
            txtReceiveMsg.Dock = DockStyle.Fill;
            txtReceiveMsg.Location = new Point(3, 19);
            txtReceiveMsg.Multiline = true;
            txtReceiveMsg.Name = "txtReceiveMsg";
            txtReceiveMsg.ReadOnly = true;
            txtReceiveMsg.ScrollBars = ScrollBars.Both;
            txtReceiveMsg.Size = new Size(663, 116);
            txtReceiveMsg.TabIndex = 0;
            //
            // txtSendMsg
            //
            txtSendMsg.Dock = DockStyle.Fill;
            txtSendMsg.Location = new Point(3, 123);
            txtSendMsg.Name = "txtSendMsg";
            txtSendMsg.Size = new Size(669, 23);
            txtSendMsg.TabIndex = 29;
            //
            // grpSetting
            //
            grpSetting.Controls.Add(txtIP);
            grpSetting.Controls.Add(txtPort);
            grpSetting.Controls.Add(lblPort);
            grpSetting.Controls.Add(cmbIP);
            grpSetting.Controls.Add(lblIP);
            grpSetting.Dock = DockStyle.Fill;
            grpSetting.Location = new Point(3, 3);
            grpSetting.Name = "grpSetting";
            grpSetting.Size = new Size(669, 94);
            grpSetting.TabIndex = 28;
            grpSetting.TabStop = false;
            grpSetting.Text = "通讯配置";
            //
            // txtIP
            //
            txtIP.Location = new Point(79, 22);
            txtIP.Name = "txtIP";
            txtIP.Size = new Size(100, 23);
            txtIP.TabIndex = 7;
            //
            // txtPort
            //
            txtPort.Location = new Point(79, 60);
            txtPort.Name = "txtPort";
            txtPort.Size = new Size(100, 23);
            txtPort.TabIndex = 6;
            //
            // lblPort
            //
            lblPort.AutoSize = true;
            lblPort.Location = new Point(13, 63);
            lblPort.Name = "lblPort";
            lblPort.Size = new Size(32, 17);
            lblPort.TabIndex = 4;
            lblPort.Text = "端口";
            //
            // cmbIP
            //
            cmbIP.FormattingEnabled = true;
            cmbIP.Location = new Point(79, 21);
            cmbIP.Name = "cmbIP";
            cmbIP.Size = new Size(100, 25);
            cmbIP.TabIndex = 1;
            //
            // lblIP
            //
            lblIP.AutoSize = true;
            lblIP.Location = new Point(13, 26);
            lblIP.Name = "lblIP";
            lblIP.Size = new Size(32, 17);
            lblIP.TabIndex = 0;
            lblIP.Text = "地址";
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 3;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 80F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 80F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Controls.Add(btnRuleSend, 1, 0);
            tableLayoutPanel2.Controls.Add(btnSend, 0, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 153);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(669, 34);
            tableLayoutPanel2.TabIndex = 27;
            //
            // btnRuleSend
            //
            btnRuleSend.Dock = DockStyle.Fill;
            btnRuleSend.Location = new Point(83, 3);
            btnRuleSend.Name = "btnRuleSend";
            btnRuleSend.Size = new Size(74, 28);
            btnRuleSend.TabIndex = 14;
            btnRuleSend.Text = "校验发送";
            btnRuleSend.UseVisualStyleBackColor = true;
            btnRuleSend.Click += btnRuleSend_Click;
            //
            // btnSend
            //
            btnSend.Dock = DockStyle.Fill;
            btnSend.Location = new Point(3, 3);
            btnSend.Name = "btnSend";
            btnSend.Size = new Size(74, 28);
            btnSend.TabIndex = 12;
            btnSend.Text = "发送";
            btnSend.UseVisualStyleBackColor = true;
            btnSend.Click += btnSend_Click;
            //
            // CommunicatorForm
            //
            AutoScaleMode = AutoScaleMode.None;
            ClientSize = new Size(681, 401);
            Controls.Add(tableLayoutPanel1);
            Name = "CommunicatorForm";
            FormClosing += CommunicatorForm_FormClosing;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel1.PerformLayout();
            grpReceive.ResumeLayout(false);
            grpReceive.PerformLayout();
            grpSetting.ResumeLayout(false);
            grpSetting.PerformLayout();
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private Label label3;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
        private GroupBox grpSetting;
        private TextBox txtIP;
        private TextBox txtPort;
        private Label lblPort;
        private ComboBox cmbIP;
        private Label lblIP;
        private TextBox txtSendMsg;
        private GroupBox grpReceive;
        private TextBox txtReceiveMsg;
        private Button btnSend;
        private Button btnRuleSend;
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,189 @@
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Communicators.TCom;
using ReaLTaiizor.Forms;
using RJCP.IO.Ports;
using System.Diagnostics;
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    public partial class CommunicatorForm : MaterialForm
    {
        BaseCommunicator communicator { get; set; }
        public CommunicatorForm()
        {
            InitializeComponent();
        }
        public CommunicatorForm(BaseCommunicator communicator, string name)
        {
            InitializeComponent();
            if (communicator == null)
                return;
            cmbIP.Enabled = false;
            txtIP.Enabled = false;
            txtPort.Enabled = false;
            this.Text = name;
            if (communicator is UARTPort)
            {
                //统计可用端口
                SerialPortStream temp = new SerialPortStream();
                string[] ArryPort = temp.GetPortNames();
                for (int i = 0; i < ArryPort.Length; i++)
                    cmbIP.Items.Add(ArryPort[i]);
                cmbIP.Text = communicator.CommunicatorConnections["地址"]?.ToString();
                txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString();
                txtIP.Visible = false;
                cmbIP.Visible = true;
                lblIP.Text = "COM口";
                lblPort.Text = "波特率";
            }
            else if (communicator is TCPClient || communicator is TCPServer)
            {
                txtIP.Text = communicator.CommunicatorConnections["地址"]?.ToString();
                txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString();
                txtIP.Visible = true;
                cmbIP.Visible = false;
                lblIP.Text = "地址";
                lblPort.Text = "端口";
            }
            else if (communicator is LocalMonitor)
            {
                txtIP.Text = communicator.CommunicatorConnections["地址"]?.ToString();
                txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString();
                txtIP.Visible = true;
                cmbIP.Visible = false;
                lblIP.Text = "监控文件";
                lblPort.Text = "写入文件";
            }
            this.communicator = communicator;
            //加载回调函数
            Subscribe();
        }
        private void CommunicatorForm_FormClosing(object sender, FormClosingEventArgs e) => Unsubscribe();
        public void Unsubscribe()
        {
            try
            {
                if (communicator == null)
                    return;
                //取消回调函数
                communicator.MessageReceived -= ShowReceiveMsg;
            }
            catch (Exception ex)
            {
                // è®°å½•错误信息
                Debug.WriteLine($"错误: {ex.Message}");
            }
        }
        public void Subscribe()
        {
            try
            {
                if (communicator == null)
                    return;
                //取消回调函数
                communicator.MessageReceived -= ShowReceiveMsg;
                //加载回调函数
                communicator.MessageReceived += ShowReceiveMsg;
            }
            catch (Exception ex)
            {
                // è®°å½•错误信息
                Debug.WriteLine($"错误: {ex.Message}");
            }
        }
        /// <summary>
        /// é€šè®¯å›žè°ƒè¿è¡Œ
        /// </summary>
        /// <param name="CCDName"></param>
        /// <param name="image"></param>
        private void ShowReceiveMsg(string strReceiveMsg)
        {
            // å¦‚果当前不是 UI çº¿ç¨‹ï¼Œåˆ™é€šè¿‡ Invoke å°†æ“ä½œè°ƒåº¦åˆ° UI çº¿ç¨‹
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>((msg) =>
                {
                    // æ›´æ–° UI æŽ§ä»¶ï¼Œæ¯”如显示接收到的消息
                    this.txtReceiveMsg.AppendText(("[接收]" + DateTime.Now.ToString() + ":" + msg));
                    this.txtReceiveMsg.AppendText("\r\n");
                    this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
                    this.txtReceiveMsg.ScrollToCaret();
                }), strReceiveMsg);
            }
            else
            {
                // å¦‚果已经在 UI çº¿ç¨‹ä¸Šï¼Œç›´æŽ¥æ›´æ–° UI
                this.txtReceiveMsg.AppendText(("[接收]" + DateTime.Now.ToString() + ":" + strReceiveMsg));
                this.txtReceiveMsg.AppendText("\r\n");
                this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
                this.txtReceiveMsg.ScrollToCaret();
            }
        }
        private void ShowSendMsg(string strSendMsg)
        {
            // å¦‚果当前不是 UI çº¿ç¨‹ï¼Œåˆ™é€šè¿‡ Invoke å°†æ“ä½œè°ƒåº¦åˆ° UI çº¿ç¨‹
            if (this.InvokeRequired)
            {
                this.Invoke(new Action<string>((msg) =>
                {
                    // æ›´æ–° UI æŽ§ä»¶ï¼Œæ¯”如显示接收到的消息
                    this.txtReceiveMsg.AppendText(("[发送]" + DateTime.Now.ToString() + ":" + msg));
                    this.txtReceiveMsg.AppendText("\r\n");
                    this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
                    this.txtReceiveMsg.ScrollToCaret();
                }), strSendMsg);
            }
            else
            {
                // å¦‚果已经在 UI çº¿ç¨‹ä¸Šï¼Œç›´æŽ¥æ›´æ–° UI
                this.txtReceiveMsg.AppendText(("[发送]" + DateTime.Now.ToString() + ":" + strSendMsg));
                this.txtReceiveMsg.AppendText("\r\n");
                this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
                this.txtReceiveMsg.ScrollToCaret();
            }
        }
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (communicator == null)
                return;
            if (communicator.SendMessage(txtSendMsg.Text))
                ShowSendMsg(txtSendMsg.Text);
        }
        private void btnRuleSend_Click(object sender, EventArgs e)
        {
            if (communicator == null)
                return;
            string SendMsg = txtSendMsg.Text;
            byte[] HexByte = BaseCommunicator.strToHexByte(SendMsg);
            ushort crcHexByte = BaseCommunicator.CRC16Calculate(HexByte, HexByte.Length);
            string crcString = crcHexByte.ToString("X4");
            //HexByte = strToHexByte(strSendMsg + crcString);
            SendMsg = SendMsg + crcString;
            if (communicator.SendMessage(SendMsg))
                ShowSendMsg(SendMsg);
        }
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorForm.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,154 @@

using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    partial class CommunicatorsEditPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            uiButton1 = new HopeButton();
            uiButton2 = new LostButton();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // uiButton1
            //
            uiButton1.BorderColor = Color.FromArgb(220, 223, 230);
            uiButton1.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            uiButton1.Cursor = Cursors.Hand;
            uiButton1.DangerColor = Color.FromArgb(245, 108, 108);
            uiButton1.DefaultColor = Color.FromArgb(255, 255, 255);
            uiButton1.Dock = DockStyle.Fill;
            uiButton1.Font = new Font("宋体", 12F);
            uiButton1.HoverTextColor = Color.FromArgb(48, 49, 51);
            uiButton1.InfoColor = Color.FromArgb(144, 147, 153);
            uiButton1.Location = new Point(503, 3);
            uiButton1.MinimumSize = new Size(1, 1);
            uiButton1.Name = "uiButton1";
            uiButton1.PrimaryColor = Color.FromArgb(64, 158, 255);
            uiButton1.Size = new Size(95, 38);
            uiButton1.SuccessColor = Color.FromArgb(103, 194, 58);
            uiButton1.TabIndex = 11;
            uiButton1.Text = "增加";
            uiButton1.TextColor = Color.White;
            uiButton1.WarningColor = Color.FromArgb(230, 162, 60);
            uiButton1.Click += uiButton1_Click;
            //
            // uiButton2
            //
            uiButton2.BackColor = Color.FromArgb(45, 45, 48);
            uiButton2.Cursor = Cursors.Hand;
            uiButton2.Dock = DockStyle.Fill;
            uiButton2.Font = new Font("宋体", 12F);
            uiButton2.ForeColor = Color.White;
            uiButton2.HoverColor = Color.DodgerBlue;
            uiButton2.Image = null;
            uiButton2.Location = new Point(403, 3);
            uiButton2.MinimumSize = new Size(1, 1);
            uiButton2.Name = "uiButton2";
            uiButton2.Size = new Size(94, 38);
            uiButton2.TabIndex = 12;
            uiButton2.Text = "清除";
            uiButton2.Click += uiButton2_Click;
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(599, 293);
            uiFlowLayoutPanel1.TabIndex = 10;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(607, 353);
            tableLayoutPanel1.TabIndex = 13;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.Controls.Add(uiButton1, 5, 0);
            tableLayoutPanel2.Controls.Add(uiButton2, 4, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 306);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(601, 44);
            tableLayoutPanel2.TabIndex = 11;
            //
            // CommunicatorsEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(tableLayoutPanel1);
            ForeColor = SystemColors.Control;
            Name = "CommunicatorsEditPage";
            Size = new Size(607, 353);
            Paint += CommunicatorsEditPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton uiButton1;
        private ReaLTaiizor.Controls.LostButton uiButton2;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,211 @@

using LB_VisionControl;
using LB_VisionProcesses.Communicators;
using VisionControl.Forms;
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    public partial class CommunicatorsEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        public CommunicatorsEditPage()
        {
            InitializeComponent();
            Name = "CommunicatorsPage";
            Text = "通讯设置";
            //this.Font = new Font("Microsoft YaHei UI", 16F, FontStyle.Regular, GraphicsUnit.Point, 0);
        }
        private void CommunicatorsEditPage_Paint(object sender, PaintEventArgs e)
        {
            uiFlowLayoutPanel1.Controls.Clear();
            if (GlobalVar.dicCommunicators.Count <= 0)
                return;
            foreach (var item in GlobalVar.dicCommunicators)
            {
                string ClassName = item.Value.GetType().Name;// "TCP"
                string IP = item.Value.CommunicatorConnections["地址"].ToString();//"127.0.0.1"
                string PORT = item.Value.CommunicatorConnections["端口"].ToString();//"1111"
                if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
                    return;
                string CommunicatorConnectionString = $"({ClassName}){IP}:{PORT}";
                UserItem flow = new UserItem(new string[] { "测试", "刷新", "移除", "重命名" });
                //flow.SetDPIScale();
                flow.Name = item.Key;
                flow.Text = CommunicatorConnectionString;
                if (item.Value.bConnected)
                    flow.state = State.Pass;
                else
                    flow.state = State.Error;
                LoadFlowEvent(flow);
                uiFlowLayoutPanel1.Controls.Add(flow);
            }
        }
        private void uiButton1_Click(object sender, System.EventArgs e)
        {
            CreateCommunicatorForm createCommunicatorForm = new CreateCommunicatorForm();
            createCommunicatorForm.ShowDialog();
            if (createCommunicatorForm.bCreate)
            {
                BaseCommunicator communicator = createCommunicatorForm.communicator;
                string Name = "通讯口" + GlobalVar.dicCommunicators.Count;
                if (GlobalVar.dicCommunicators.ContainsKey(Name))
                    Name += "副本";
                string ClassName = communicator.GetType().Name;// "TCP"
                string IP = communicator.CommunicatorConnections["地址"].ToString();//"127.0.0.1"
                string PORT = communicator.CommunicatorConnections["端口"].ToString();//"1111"
                if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
                    return;
                string CommunicatorConnectionString = $"({ClassName}){IP}:{PORT}";
                GlobalVar.dicCommunicators.TryAdd(Name, communicator);
                communicator.CommunicatorName = Name;
                LogInfo?.Invoke(string.Format("添加通讯口[{0}]成功", Name), LogInfoType.PASS);
            }
            this.Invalidate();
        }
        private void uiButton2_Click(object sender, System.EventArgs e)
        {
            //清除用Clear方法
            uiFlowLayoutPanel1.Controls.Clear();
            foreach (var communicator in GlobalVar.dicCommunicators.Values)
            {
                communicator.Disconnect();
            }
            GlobalVar.dicCommunicators.Clear();
            this.Refresh();
        }
        private void LoadFlowEvent(UserItem flow)
        {
            //按键1为测试
            flow.MenuItem1ClickedEvent += TestEvent;
            //按键2为刷新
            flow.MenuItem2ClickedEvent += ReconnectEvent;
            //按键3为移除
            flow.MenuItem3ClickedEvent += DeleteEvent;
            //按键4为重命名
            flow.MenuItem4ClickedEvent += RenameEvent;
        }
        private void RemoveFlowEvent(UserItem flow)
        {
            //按键1为测试
            flow.MenuItem1ClickedEvent -= TestEvent;
            //按键2为刷新
            flow.MenuItem2ClickedEvent -= ReconnectEvent;
            //按键3为移除
            flow.MenuItem3ClickedEvent -= DeleteEvent;
            //按键4为重命名
            flow.MenuItem4ClickedEvent -= RenameEvent;
        }
        // æµ‹è¯•通讯口
        private void TestEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                if (GlobalVar.dicCommunicators.ContainsKey(name))
                {
                    CommunicatorForm cameraForm = new CommunicatorForm(GlobalVar.dicCommunicators[name], name);
                    cameraForm.Show();
                }
            }
        }
        // ç§»é™¤é€šè®¯å£
        private void DeleteEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                RemoveFlowEvent(flow);
                uiFlowLayoutPanel1.Controls.Remove(uiFlowLayoutPanel1.Controls[i]);
                GlobalVar.dicCommunicators.TryRemove(name, out BaseCommunicator BaseCommunicator);
                if (BaseCommunicator != null)
                    LogInfo?.Invoke(string.Format("移除通讯口[{0}]", name), LogInfoType.INFO);
            }
        }
        private void RenameEvent(string Name, string Text)
        {
            RenameForm renameForm = new RenameForm(Name);
            // è®¢é˜…事件
            renameForm.ShowDialog();
            if (!renameForm.bRename)
                return;
            if (GlobalVar.dicCommunicators.ContainsKey(renameForm.strNewName))
            {
                MessageBox.Show("命名重复!", "异常");
                return;
            }
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                flow.Name = renameForm.strNewName;
                string oldName = name;
                string newName = renameForm.strNewName;
                if (GlobalVar.dicCommunicators.ContainsKey(oldName))
                    GlobalVar.dicCommunicators.TryRename(oldName, newName);
                flow.Refresh();
            }
        }
        // é‡è¿žæµç¨‹
        private void ReconnectEvent(string Name, string Text)
        {
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                GlobalVar.dicCommunicators[name].Disconnect();
                Thread.Sleep(50);
                GlobalVar.dicCommunicators[name].Connect();
                if (GlobalVar.dicCommunicators[name].bConnected)
                {
                    flow.state = State.Pass;
                    LogInfo?.Invoke(string.Format("重连通讯口[{0}]成功", name), LogInfoType.PASS);
                }
                else
                {
                    flow.state = State.Error;
                    LogInfo?.Invoke(string.Format("重连通讯口[{0}]失败", name), LogInfoType.ERROR);
                }
                flow.Refresh();
            }
        }
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CommunicatorsEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,251 @@
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    partial class CreateCommunicatorForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            uiLabelIP = new Label();
            uiLabelPort = new Label();
            uiButtonCancel = new Button();
            uiTextBoxPort = new TextBox();
            rButtonUART = new RadioButton();
            rButtonTCPServer = new RadioButton();
            rButtonTCPClient = new RadioButton();
            uiButtonCreate = new Button();
            uiButtonTest = new Button();
            uiComboBoxPort = new ComboBox();
            uiIPTextBox = new TextBox();
            uiTextBoxPath = new TextBox();
            rButtonMonitor = new RadioButton();
            SuspendLayout();
            //
            // uiLabelIP
            //
            uiLabelIP.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiLabelIP.ForeColor = Color.FromArgb(48, 48, 48);
            uiLabelIP.Location = new Point(84, 111);
            uiLabelIP.Name = "uiLabelIP";
            uiLabelIP.Size = new Size(100, 23);
            uiLabelIP.TabIndex = 1;
            uiLabelIP.Text = "地址";
            //
            // uiLabelPort
            //
            uiLabelPort.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiLabelPort.ForeColor = Color.FromArgb(48, 48, 48);
            uiLabelPort.Location = new Point(84, 177);
            uiLabelPort.Name = "uiLabelPort";
            uiLabelPort.Size = new Size(100, 23);
            uiLabelPort.TabIndex = 2;
            uiLabelPort.Text = "端口";
            //
            // uiButtonCancel
            //
            uiButtonCancel.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiButtonCancel.Location = new Point(343, 234);
            uiButtonCancel.MinimumSize = new Size(1, 1);
            uiButtonCancel.Name = "uiButtonCancel";
            uiButtonCancel.Size = new Size(100, 35);
            uiButtonCancel.TabIndex = 4;
            uiButtonCancel.Text = "取消";
            uiButtonCancel.Click += uiButtonCancel_Click;
            //
            // uiTextBoxPort
            //
            uiTextBoxPort.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiTextBoxPort.Location = new Point(191, 175);
            uiTextBoxPort.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxPort.MinimumSize = new Size(1, 16);
            uiTextBoxPort.Name = "uiTextBoxPort";
            uiTextBoxPort.Padding = new Padding(5);
            //uiTextBoxPort.ShowText = false;
            uiTextBoxPort.Size = new Size(205, 29);
            uiTextBoxPort.TabIndex = 5;
            //uiTextBoxPort.TextAlignment = ContentAlignment.MiddleLeft;
            //uiTextBoxPort.Watermark = "";
            uiTextBoxPort.TextChanged += uiTextBoxPort_TextChanged;
            //
            // rButtonUART
            //
            rButtonUART.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            rButtonUART.Location = new Point(51, 12);
            rButtonUART.MinimumSize = new Size(1, 1);
            rButtonUART.Name = "rButtonUART";
            rButtonUART.Size = new Size(150, 29);
            rButtonUART.TabIndex = 6;
            rButtonUART.Text = "串口通讯";
            rButtonUART.CheckedChanged += rButtonUART_CheckedChanged;
            //
            // rButtonTCPServer
            //
            rButtonTCPServer.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            rButtonTCPServer.Location = new Point(51, 47);
            rButtonTCPServer.MinimumSize = new Size(1, 1);
            rButtonTCPServer.Name = "rButtonTCPServer";
            rButtonTCPServer.Size = new Size(150, 29);
            rButtonTCPServer.TabIndex = 7;
            rButtonTCPServer.Text = "TCP服务器";
            rButtonTCPServer.CheckedChanged += rButtonTCPServer_CheckedChanged;
            //
            // rButtonTCPClient
            //
            rButtonTCPClient.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            rButtonTCPClient.Location = new Point(293, 47);
            rButtonTCPClient.MinimumSize = new Size(1, 1);
            rButtonTCPClient.Name = "rButtonTCPClient";
            rButtonTCPClient.Size = new Size(150, 29);
            rButtonTCPClient.TabIndex = 8;
            rButtonTCPClient.Text = "TCP客户端";
            rButtonTCPClient.CheckedChanged += rButtonTCPClient_CheckedChanged;
            //
            // uiButtonCreate
            //
            uiButtonCreate.Enabled = false;
            uiButtonCreate.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiButtonCreate.Location = new Point(191, 234);
            uiButtonCreate.MinimumSize = new Size(1, 1);
            uiButtonCreate.Name = "uiButtonCreate";
            uiButtonCreate.Size = new Size(100, 35);
            uiButtonCreate.TabIndex = 9;
            uiButtonCreate.Text = "创建";
            uiButtonCreate.Click += uiButtonCreate_Click;
            //
            // uiButtonTest
            //
            uiButtonTest.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiButtonTest.Location = new Point(31, 234);
            uiButtonTest.MinimumSize = new Size(1, 1);
            uiButtonTest.Name = "uiButtonTest";
            uiButtonTest.Size = new Size(100, 35);
            uiButtonTest.TabIndex = 10;
            uiButtonTest.Text = "测试";
            uiButtonTest.Click += uiButtonTest_Click;
            //
            // uiComboBoxPort
            //
            uiComboBoxPort.DataSource = null;
            //uiComboBoxPort.FillColor = Color.White;
            uiComboBoxPort.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            //uiComboBoxPort.ItemHoverColor = Color.FromArgb(155, 200, 255);
            //uiComboBoxPort.ItemSelectForeColor = Color.FromArgb(235, 243, 255);
            uiComboBoxPort.Location = new Point(191, 108);
            uiComboBoxPort.Margin = new Padding(4, 5, 4, 5);
            uiComboBoxPort.MinimumSize = new Size(63, 0);
            uiComboBoxPort.Name = "uiComboBoxPort";
            uiComboBoxPort.Padding = new Padding(0, 0, 30, 2);
            uiComboBoxPort.Size = new Size(205, 29);
            //uiComboBoxPort.SymbolSize = 24;
            uiComboBoxPort.TabIndex = 11;
            //uiComboBoxPort.TextAlignment = ContentAlignment.MiddleLeft;
            //uiComboBoxPort.Watermark = "";
            uiComboBoxPort.MouseClick += uiComboBoxPort_MouseClick;
            //
            // uiIPTextBox
            //
            //uiIPTextBox.FillColor2 = Color.FromArgb(235, 243, 255);
            uiIPTextBox.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiIPTextBox.Location = new Point(191, 108);
            uiIPTextBox.Margin = new Padding(4, 5, 4, 5);
            uiIPTextBox.MinimumSize = new Size(1, 1);
            uiIPTextBox.Name = "uiIPTextBox";
            uiIPTextBox.Padding = new Padding(1);
            //uiIPTextBox.ShowText = false;
            uiIPTextBox.Size = new Size(205, 29);
            uiIPTextBox.TabIndex = 12;
            //uiIPTextBox.TextAlignment = ContentAlignment.MiddleCenter;
            uiIPTextBox.MouseClick += uiIPTextBox_MouseClick;
            //
            // uiTextBoxPath
            //
            uiTextBoxPath.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            uiTextBoxPath.Location = new Point(191, 108);
            uiTextBoxPath.Margin = new Padding(4, 5, 4, 5);
            uiTextBoxPath.MinimumSize = new Size(1, 16);
            uiTextBoxPath.Name = "uiTextBoxPath";
            uiTextBoxPath.Padding = new Padding(5);
            //uiTextBoxPath.ShowText = false;
            uiTextBoxPath.Size = new Size(205, 29);
            uiTextBoxPath.TabIndex = 13;
            //uiTextBoxPath.TextAlignment = ContentAlignment.MiddleLeft;
            //uiTextBoxPath.Watermark = "";
            //
            // rButtonMonitor
            //
            rButtonMonitor.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point);
            rButtonMonitor.Location = new Point(293, 12);
            rButtonMonitor.MinimumSize = new Size(1, 1);
            rButtonMonitor.Name = "rButtonMonitor";
            rButtonMonitor.Size = new Size(150, 29);
            rButtonMonitor.TabIndex = 14;
            rButtonMonitor.Text = "本地监控";
            rButtonMonitor.CheckedChanged += rButtonMonitor_CheckedChanged;
            //
            // CreateCommunicatorForm
            //
            //AllowShowTitle = false;
            AutoScaleMode = AutoScaleMode.None;
            ClientSize = new Size(484, 285);
            ControlBox = false;
            Controls.Add(rButtonMonitor);
            Controls.Add(uiTextBoxPath);
            Controls.Add(uiIPTextBox);
            Controls.Add(uiComboBoxPort);
            Controls.Add(uiTextBoxPort);
            Controls.Add(uiButtonTest);
            Controls.Add(uiButtonCreate);
            Controls.Add(rButtonTCPClient);
            Controls.Add(rButtonTCPServer);
            Controls.Add(rButtonUART);
            Controls.Add(uiButtonCancel);
            Controls.Add(uiLabelPort);
            Controls.Add(uiLabelIP);
            MaximizeBox = false;
            MinimizeBox = false;
            Name = "CreateCommunicatorForm";
            Padding = new Padding(0);
            //ShowTitle = false;
            Text = "创建通讯";
            //ZoomScaleRect = new Rectangle(15, 15, 800, 450);
            ResumeLayout(false);
        }
        #endregion
        private Label uiLabelIP;
        private Label uiLabelPort;
        private Button uiButtonCancel;
        private TextBox uiTextBoxPort;
        private RadioButton rButtonUART;
        private RadioButton rButtonTCPServer;
        private RadioButton rButtonTCPClient;
        private Button uiButtonCreate;
        private Button uiButtonTest;
        private ComboBox uiComboBoxPort;
        private TextBox uiIPTextBox;
        private TextBox uiTextBoxPath;
        private RadioButton rButtonMonitor;
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Communicators.TCom;
using RJCP.IO.Ports;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
{
    public partial class CreateCommunicatorForm : Form
    {
        public BaseCommunicator communicator { get; set; }
        public bool bCreate = false;
        public CreateCommunicatorForm(BaseCommunicator communicator = null)
        {
            InitializeComponent();
            // ç¦æ­¢ä¿®æ”¹çª—口大小
            this.FormBorderStyle = FormBorderStyle.FixedDialog;
            if (communicator == null)
                communicator = new UARTPort();
            rButtonUART.Checked = true;
            uiButtonCreate.Enabled = false;
        }
        private void uiButtonTest_Click(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            rButtonUART.Enabled = false;
            rButtonTCPServer.Enabled = false;
            rButtonTCPClient.Enabled = false;
            rButtonMonitor.Enabled = false;
            if (communicator != null)
                communicator.Disconnect();
            if (rButtonUART.Checked)
            {
                communicator = new UARTPort();
                IP = uiComboBoxPort.Text;
                PORT = uiTextBoxPort.Text;
            }
            else if (rButtonTCPServer.Checked)
            {
                communicator = new TCPServer();
                IP = uiIPTextBox.Text;
                PORT = uiTextBoxPort.Text;
            }
            else if (rButtonTCPClient.Checked)
            {
                communicator = new TCPClient();
                IP = uiIPTextBox.Text;
                PORT = uiTextBoxPort.Text;
            }
            else if (rButtonMonitor.Checked)
            {
                communicator = new LocalMonitor();
                IP = uiTextBoxPath.Text;
                PORT = uiTextBoxPort.Text;
            }
            else
            {
                MessageBox.Show("未选择通讯类型!", "异常");
                return;
            }
            communicator.CommunicatorConnections.Add("地址", IP);
            communicator.CommunicatorConnections.Add("端口", PORT);
            if (communicator.Connect())
            {
                uiButtonCreate.Enabled = true;
                communicator.Disconnect();
            }
            else
                MessageBox.Show($"初始化通讯口失败,原因是:{communicator.Msg}", "异常");
        }
        public string IP = string.Empty;
        public string PORT = string.Empty;
        private void uiButtonCreate_Click(object sender, EventArgs e)
        {
            if (communicator.Connect())
            {
                bCreate = true;
                this.Close();
            }
            else
                MessageBox.Show($"初始化通讯口失败,原因是:{communicator.Msg}", "异常");
        }
        private void uiButtonCancel_Click(object sender, EventArgs e)
        {
            if (communicator != null)
                communicator.Disconnect();
            bCreate = false;
            this.Close();
        }
        private void rButtonUART_CheckedChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            if (communicator != null)
                communicator.Disconnect();
            if (rButtonUART.Checked)
            {
                uiLabelIP.Visible = true;
                uiLabelIP.Text = "COM口";
                uiIPTextBox.Visible = false;
                uiComboBoxPort.Visible = true;
                uiTextBoxPath.Visible = false;
                uiLabelPort.Visible = true;
                uiLabelPort.Text = "波特率";
                uiTextBoxPort.Visible = true;
                uiButtonCreate.Enabled = false;
            }
        }
        private void rButtonTCPServer_CheckedChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            if (communicator != null)
                communicator.Disconnect();
            if (rButtonTCPServer.Checked)
            {
                uiLabelIP.Visible = true;
                uiLabelIP.Text = "地址";
                uiIPTextBox.Visible = true;
                uiComboBoxPort.Visible = false;
                uiTextBoxPath.Visible = false;
                uiLabelPort.Visible = true;
                uiLabelPort.Text = "端口";
                uiTextBoxPort.Visible = true;
                uiButtonCreate.Enabled = false;
            }
        }
        private void rButtonTCPClient_CheckedChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            if (communicator != null)
                communicator.Disconnect();
            if (rButtonTCPClient.Checked)
            {
                uiLabelIP.Visible = true;
                uiLabelIP.Text = "地址";
                uiIPTextBox.Visible = true;
                uiComboBoxPort.Visible = false;
                uiTextBoxPath.Visible = false;
                uiLabelPort.Visible = true;
                uiLabelPort.Text = "端口";
                uiTextBoxPort.Visible = true;
            }
        }
        private void rButtonMonitor_CheckedChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
            if (communicator != null)
                communicator.Disconnect();
            if (rButtonMonitor.Checked)
            {
                uiLabelIP.Visible = true;
                uiLabelIP.Text = "监控文件";
                uiIPTextBox.Visible = false;
                uiComboBoxPort.Visible = false;
                uiTextBoxPath.Visible = true;
                uiLabelPort.Visible = true;
                uiLabelPort.Text = "写入文件";
                uiTextBoxPort.Visible = true;
            }
        }
        private void uiComboBoxPort_MouseClick(object sender, MouseEventArgs e)
        {
            uiButtonCreate.Enabled = false;
            uiComboBoxPort.Text = string.Empty;
            uiComboBoxPort.Items.Clear();
            //统计可用端口
            SerialPortStream temp = new SerialPortStream();
            string[] ArryPort = temp.GetPortNames();
            for (int i = 0; i < ArryPort.Length; i++)
                uiComboBoxPort.Items.Add(ArryPort[i]);
        }
        private void uiTextBoxPort_TextChanged(object sender, EventArgs e)
        {
            uiButtonCreate.Enabled = false;
        }
        private void uiIPTextBox_MouseClick(object sender, MouseEventArgs e)
        {
            uiButtonCreate.Enabled = false;
        }
    }
}
LB_SmartVision/Forms/Pages/CommunicatorPage/CreateCommunicatorForm.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,152 @@

using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.MESPage
{
    partial class MESEditPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            uiButton1 = new HopeButton();
            uiButton2 = new LostButton();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // uiButton1
            //
            uiButton1.BorderColor = Color.FromArgb(220, 223, 230);
            uiButton1.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            uiButton1.Cursor = Cursors.Hand;
            uiButton1.DangerColor = Color.FromArgb(245, 108, 108);
            uiButton1.DefaultColor = Color.FromArgb(255, 255, 255);
            uiButton1.Dock = DockStyle.Fill;
            uiButton1.Font = new Font("宋体", 12F);
            uiButton1.HoverTextColor = Color.FromArgb(48, 49, 51);
            uiButton1.InfoColor = Color.FromArgb(144, 147, 153);
            uiButton1.Location = new Point(503, 3);
            uiButton1.MinimumSize = new Size(1, 1);
            uiButton1.Name = "uiButton1";
            uiButton1.PrimaryColor = Color.FromArgb(64, 158, 255);
            uiButton1.Size = new Size(95, 38);
            uiButton1.SuccessColor = Color.FromArgb(103, 194, 58);
            uiButton1.TabIndex = 11;
            uiButton1.Text = "增加";
            uiButton1.TextColor = Color.White;
            uiButton1.WarningColor = Color.FromArgb(230, 162, 60);
            //
            // uiButton2
            //
            uiButton2.BackColor = Color.FromArgb(45, 45, 48);
            uiButton2.Cursor = Cursors.Hand;
            uiButton2.Dock = DockStyle.Fill;
            uiButton2.Font = new Font("宋体", 12F);
            uiButton2.ForeColor = Color.White;
            uiButton2.HoverColor = Color.DodgerBlue;
            uiButton2.Image = null;
            uiButton2.Location = new Point(403, 3);
            uiButton2.MinimumSize = new Size(1, 1);
            uiButton2.Name = "uiButton2";
            uiButton2.Size = new Size(94, 38);
            uiButton2.TabIndex = 12;
            uiButton2.Text = "清除";
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(599, 293);
            uiFlowLayoutPanel1.TabIndex = 10;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(607, 353);
            tableLayoutPanel1.TabIndex = 13;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.Controls.Add(uiButton1, 5, 0);
            tableLayoutPanel2.Controls.Add(uiButton2, 4, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.ForeColor = SystemColors.Control;
            tableLayoutPanel2.Location = new Point(3, 306);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(601, 44);
            tableLayoutPanel2.TabIndex = 11;
            //
            // MESEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(tableLayoutPanel1);
            Name = "MESEditPage";
            Size = new Size(607, 353);
            Paint += MESEditPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton uiButton1;
        private ReaLTaiizor.Controls.LostButton uiButton2;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
    }
}
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
using LB_VisionControl;
using OpenCvSharp.Flann;
using System;
using System.Collections.Concurrent;
using System.Windows.Forms;
using System.Xml.Linq;
namespace LB_SmartVision.Forms.Pages.MESPage
{
    public partial class MESEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        public MESEditPage()
        {
            InitializeComponent();
            Name = "MESEditPage";
            Text = "MES设置";
        }
        private void MESEditPage_Paint(object sender, PaintEventArgs e)
        {
            uiFlowLayoutPanel1.Controls.Clear();
        }
    }
}
LB_SmartVision/Forms/Pages/MESPage/MESEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,152 @@

using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.MotionControlPage
{
    partial class MotionControlEditPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            uiButton1 = new HopeButton();
            uiButton2 = new LostButton();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // uiButton1
            //
            uiButton1.BorderColor = Color.FromArgb(220, 223, 230);
            uiButton1.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            uiButton1.Cursor = Cursors.Hand;
            uiButton1.DangerColor = Color.FromArgb(245, 108, 108);
            uiButton1.DefaultColor = Color.FromArgb(255, 255, 255);
            uiButton1.Dock = DockStyle.Fill;
            uiButton1.Font = new Font("宋体", 12F);
            uiButton1.HoverTextColor = Color.FromArgb(48, 49, 51);
            uiButton1.InfoColor = Color.FromArgb(144, 147, 153);
            uiButton1.Location = new Point(503, 3);
            uiButton1.MinimumSize = new Size(1, 1);
            uiButton1.Name = "uiButton1";
            uiButton1.PrimaryColor = Color.FromArgb(64, 158, 255);
            uiButton1.Size = new Size(95, 38);
            uiButton1.SuccessColor = Color.FromArgb(103, 194, 58);
            uiButton1.TabIndex = 11;
            uiButton1.Text = "增加";
            uiButton1.TextColor = Color.White;
            uiButton1.WarningColor = Color.FromArgb(230, 162, 60);
            //
            // uiButton2
            //
            uiButton2.BackColor = Color.FromArgb(45, 45, 48);
            uiButton2.Cursor = Cursors.Hand;
            uiButton2.Dock = DockStyle.Fill;
            uiButton2.Font = new Font("宋体", 12F);
            uiButton2.ForeColor = Color.White;
            uiButton2.HoverColor = Color.DodgerBlue;
            uiButton2.Image = null;
            uiButton2.Location = new Point(403, 3);
            uiButton2.MinimumSize = new Size(1, 1);
            uiButton2.Name = "uiButton2";
            uiButton2.Size = new Size(94, 38);
            uiButton2.TabIndex = 12;
            uiButton2.Text = "清除";
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(599, 293);
            uiFlowLayoutPanel1.TabIndex = 10;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(607, 353);
            tableLayoutPanel1.TabIndex = 13;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.Controls.Add(uiButton1, 5, 0);
            tableLayoutPanel2.Controls.Add(uiButton2, 4, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 306);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(601, 44);
            tableLayoutPanel2.TabIndex = 11;
            //
            // MotionControlEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(tableLayoutPanel1);
            ForeColor = SystemColors.Control;
            Name = "MotionControlEditPage";
            Size = new Size(607, 353);
            Paint += MESEditPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton uiButton1;
        private ReaLTaiizor.Controls.LostButton uiButton2;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
    }
}
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
using LB_VisionControl;
using OpenCvSharp.Flann;
using System;
using System.Collections.Concurrent;
using System.Windows.Forms;
using System.Xml.Linq;
namespace LB_SmartVision.Forms.Pages.MotionControlPage
{
    public partial class MotionControlEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        public MotionControlEditPage()
        {
            InitializeComponent();
            Name = "MotionControlEditPage";
            Text = "运动控制设置";
        }
        private void MESEditPage_Paint(object sender, PaintEventArgs e)
        {
            uiFlowLayoutPanel1.Controls.Clear();
        }
    }
}
LB_SmartVision/Forms/Pages/MotionControlPage/MotionControlEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/MyPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages
{
    public class MyPage : TabPage
    {
        public UserControl UserControl;
        public MyPage()
        {
            UserControl = new UserControl();
            UserControl.Dock = DockStyle.Fill;
            Name = "UserControl";
            Text = "用户控件";
            this.Controls.Add(UserControl);
        }
        public MyPage(UserControl _userControl)
        {
            this.UserControl = _userControl;
            this.UserControl.Dock = DockStyle.Fill;
            Name = _userControl.Name;
            Text = _userControl.Text;
            this.Controls.Add(this.UserControl);
        }
    }
}
LB_SmartVision/Forms/Pages/MyPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,56 @@
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class AllProcessesPage
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            controlsPanel = new Panel();
            SuspendLayout();
            //
            // controlsPanel
            //
            controlsPanel.Dock = DockStyle.Fill;
            controlsPanel.Location = new Point(0, 0);
            controlsPanel.Name = "controlsPanel";
            controlsPanel.Size = new Size(803, 478);
            controlsPanel.TabIndex = 0;
            //
            // AllProcessesPage
            //
            //AutoScaleDimensions = new SizeF(7F, 17F);
            //AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(controlsPanel);
            Name = "AllProcessesPage";
            Size = new Size(803, 478);
            ResumeLayout(false);
        }
        #endregion
        public Panel controlsPanel;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
using HalconDotNet;
using LB_SmartVision.Tool;
using System.Data;
using System.Runtime.InteropServices;
using System.Xml.Linq;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class AllProcessesPage : TabPage
    {
        public ObservableConcurrentDictionary<string, ProcessControl> dicProcessControls = new ObservableConcurrentDictionary<string, ProcessControl>();
        /// <summary>
        /// å®žä¾‹åŒ–流程界面
        /// </summary>
        /// <param name="dicProcesses"></param>
        public AllProcessesPage()
        {
            InitializeComponent();
            Name = "AllProcessesPage";
            Text = "主界面";
            //this.Font = new Font("Microsoft YaHei UI", 16F, FontStyle.Regular, GraphicsUnit.Point, 0);
            this.BackColor = Color.FromArgb(32, 41, 50);
            InitVisionUI();
            this.Invalidated += AllProcessesPage_Invalidated;
        }
        private void AllProcessesPage_Invalidated(object? sender, InvalidateEventArgs e) => InitVisionUI();
        public void InitVisionUI()
        {
            List<string> keys = dicProcessControls.Keys.ToList();
            foreach (var title in keys)
            {
                bool isExist = false;
                foreach (var layout in GlobalVar.dicLayout.Values)
                {
                    if (layout.Title == title)
                    {
                        isExist = true;
                        break;
                    }
                }
                if (!isExist)
                {
                    if (dicProcessControls.ContainsKey(title))
                    {
                        this.controlsPanel.Controls.Remove(dicProcessControls[title]);
                        dicProcessControls.TryRemove(title, out _);
                    }
                }
            }
            int enableLayout = 0;
            foreach (var layout in GlobalVar.dicLayout.Values)
            {
                if (GlobalVar.dicProcesses.ContainsKey(layout.ProcessName))
                    enableLayout++;
            }
            int index = 0;
            for (int i = 0; i < GlobalVar.dicLayout.Count; i++)
            {
                string name = GlobalVar.dicLayout[i].ProcessName;
                string title = GlobalVar.dicLayout[i].Title;
                if (GlobalVar.dicProcesses.ContainsKey(name))
                {
                    if (dicProcessControls.ContainsKey(title))
                    {
                        ProcessControl processControl = dicProcessControls[title];
                        processControl.Size
                            = new Size(this.controlsPanel.Size.Width / enableLayout
                            , this.controlsPanel.Size.Height);
                        processControl.Location
                            = new Point(processControl.Size.Width * index, 0);
                        if (GlobalVar.dicProcesses[name].GetImage(GlobalVar.dicLayout[i], out _, out HObject RecordImage))
                            dicProcessControls[title].ShowHoImage(RecordImage);
                    }
                    else
                    {
                        ProcessControl processControl = new ProcessControl(GlobalVar.dicLayout[i]);
                        processControl.Size
                            = new Size(this.controlsPanel.Size.Width / enableLayout
                            , this.controlsPanel.Size.Height);
                        processControl.Location
                            = new Point(processControl.Size.Width * index, 0);
                        processControl.SetTitle(title);
                        dicProcessControls.TryAdd(title, processControl);
                        this.controlsPanel.Controls.Add(processControl);
                        if (GlobalVar.dicProcesses[name].GetImage(GlobalVar.dicLayout[i], out _, out HObject RecordImage))
                            dicProcessControls[title].ShowHoImage(RecordImage);
                    }
                    index++;
                }
            }
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/AllProcessesPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class ProcessControl
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            toolStrip1 = new ToolStrip();
            lblTitle = new ToolStripLabel();
            btnRun = new ToolStripButton();
            btnCircleRun = new ToolStripButton();
            panel1 = new Panel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            label1 = new Label();
            toolStrip1.SuspendLayout();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // toolStrip1
            //
            toolStrip1.BackColor = Color.FromArgb(32, 41, 50);
            toolStrip1.Items.AddRange(new ToolStripItem[] { lblTitle, btnRun, btnCircleRun });
            toolStrip1.Location = new Point(0, 0);
            toolStrip1.Name = "toolStrip1";
            toolStrip1.Size = new Size(360, 25);
            toolStrip1.TabIndex = 0;
            toolStrip1.Text = "toolStrip1";
            //
            // lblTitle
            //
            lblTitle.BackColor = SystemColors.ActiveCaptionText;
            lblTitle.Name = "lblTitle";
            lblTitle.Size = new Size(56, 22);
            lblTitle.Text = "流程名称";
            //
            // btnRun
            //
            btnRun.ImageTransparentColor = Color.Magenta;
            btnRun.Name = "btnRun";
            btnRun.Size = new Size(60, 22);
            btnRun.Text = "单次运行";
            btnRun.ToolTipText = "单次运行";
            btnRun.Click += btnRun_Click;
            //
            // btnCircleRun
            //
            btnCircleRun.ImageTransparentColor = Color.Magenta;
            btnCircleRun.Name = "btnCircleRun";
            btnCircleRun.Size = new Size(60, 22);
            btnCircleRun.Text = "连续运行";
            btnCircleRun.ToolTipText = "连续";
            btnCircleRun.Click += btnCircleRun_Click;
            //
            // panel1
            //
            panel1.BackColor = Color.FromArgb(32, 41, 50);
            panel1.Dock = DockStyle.Fill;
            panel1.Location = new Point(3, 3);
            panel1.Name = "panel1";
            panel1.Size = new Size(354, 187);
            panel1.TabIndex = 1;
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(panel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 25);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 22F));
            tableLayoutPanel1.Size = new Size(360, 215);
            tableLayoutPanel1.TabIndex = 2;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel2.ColumnCount = 3;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333321F));
            tableLayoutPanel2.Controls.Add(label1, 0, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 196);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(354, 16);
            tableLayoutPanel2.TabIndex = 2;
            //
            // label1
            //
            label1.AutoSize = true;
            label1.BackColor = Color.FromArgb(32, 41, 50);
            label1.Dock = DockStyle.Fill;
            label1.Location = new Point(3, 0);
            label1.Name = "label1";
            label1.Size = new Size(112, 16);
            label1.TabIndex = 0;
            label1.Text = "总数:0";
            label1.DoubleClick += lblCount_DoubleClick;
            label1.MouseHover += lblCount_MouseHover;
            //
            // ProcessControl
            //
            AutoScaleDimensions = new SizeF(96F, 96F);
            AutoScaleMode = AutoScaleMode.Dpi;
            BackColor = SystemColors.Control;
            Controls.Add(tableLayoutPanel1);
            Controls.Add(toolStrip1);
            ForeColor = SystemColors.Control;
            Name = "ProcessControl";
            Size = new Size(360, 240);
            Load += ProcessControl_Load;
            toolStrip1.ResumeLayout(false);
            toolStrip1.PerformLayout();
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            tableLayoutPanel2.PerformLayout();
            ResumeLayout(false);
            PerformLayout();
        }
        #endregion
        private ToolStrip toolStrip1;
        private ToolStripButton btnRun;
        private ToolStripLabel lblTitle;
        private Panel panel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
        private Label label1;
        private ToolStripButton btnCircleRun;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,220 @@
using HalconDotNet;
using LB_SmartVision.ProcessRun;
using LB_VisionControl;
using Layout = LB_SmartVision.Forms.Pages.SettingPage.Layout;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class ProcessControl : UserControl
    {
        UserHSmartWindowControl UserHSmartWindowControl = new UserHSmartWindowControl();
        ProcessRunBll ProcessRunBll
        {
            get
            {
                if (GlobalVar.dicProcesses.ContainsKey(_Layout.ProcessName))
                    return GlobalVar.dicProcesses[_Layout.ProcessName];
                else
                    return null;
            }
        }
        Layout _Layout { get; set; } = new Layout();
        public ProcessControl()
        {
            InitializeComponent();
        }
        public ProcessControl(Layout layout)
        {
            InitializeComponent();
            _Layout = layout;
        }
        private void ProcessControl_Load(object sender, EventArgs e)
        {
            this.panel1.Controls.Add(this.UserHSmartWindowControl);
            this.UserHSmartWindowControl.Dock = DockStyle.Fill;
            SetTitle(_Layout.ProcessName);
            if (ProcessRunBll != null)
                this.label1.Text = $"总数:{ProcessRunBll.total}";
        }
        public void SetTitle(string title)
        {
            // å¦‚果当前不是 UI çº¿ç¨‹ï¼Œåˆ™é€šè¿‡ Invoke å°†æ“ä½œè°ƒåº¦åˆ° UI çº¿ç¨‹
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new Action<string>((title) =>
                {
                    this.lblTitle.Text = title;
                }), title);
            }
            else
            {
                // å¦‚果已经在 UI çº¿ç¨‹ä¸Šï¼Œç›´æŽ¥æ›´æ–°
                this.lblTitle.Text = title;
            }
        }
        public void ClearObj()
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new Action(() =>
                {
                    UserHSmartWindowControl.ClearObj();
                }));
            }
            else
                UserHSmartWindowControl.ClearObj();
        }
        /// <summary>
        /// å¼‚步显示图片
        /// </summary>
        /// <param name="ho_image"></param>
        public void ShowHoImage(HObject ho_image)
        {
            UserHSmartWindowControl.hImage = ho_image;
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new Action(() =>
                {
                    this.label1.Text = $"总数:{ProcessRunBll.total}";
                }));
            }
            else
                this.label1.Text = $"总数:{ProcessRunBll.total}";
        }
        public bool Run(out string msg)
        {
            if (ProcessRunBll == null)
            {
                msg = $"流程{_Layout.ProcessName}不存在";
                return false;
            }
            if (isCircleRuning || ProcessRunBll.bPruning)
                ProcessRunBll.LogInfo($"{ProcessRunBll.Name}正在运行", LogInfoType.ERROR);
            ProcessRunBll.Run();
            msg = ProcessRunBll.Msg;
            return ProcessRunBll.Result;
        }
        private void btnRun_Click(object sender, EventArgs e)
        {
            this.BeginInvoke(new Action(() =>
            {
                string msg = string.Empty;
                bool result = false;
                try
                {
                    if (ProcessRunBll == null)
                        return;
                    ProcessRunBll.LogInfo(string.Format("流程[{0}]开始运行", this.ProcessRunBll.Name), LogInfoType.INFO);
                    ClearObj();
                    result = Run(out msg);
                    if (ProcessRunBll.GetImage(_Layout, out _, out HObject RecordImage))
                        ShowHoImage(RecordImage);
                }
                catch { msg = "运行出现了异常"; }
                ProcessRunBll.LogInfo(string.Format("流程[{0}]运行完成,结果:{1}", this.ProcessRunBll.Name, msg)
                , result ? LogInfoType.PASS : LogInfoType.ERROR);
            }));
        }
        CancellationTokenSource ctsTask = new CancellationTokenSource();
        bool isCircleRuning = false;
        private void btnCircleRun_Click(object sender, EventArgs e)
        {
            try
            {
                isCircleRuning = !isCircleRuning;
                btnRun.Enabled = !isCircleRuning;
                if (isCircleRuning)
                {
                    threadCircleRun = new Thread(ThreadCircleRun);
                    threadCircleRun.IsBackground = true;
                    threadCircleRun.Start();
                }
                else
                {
                    isCircleRuning = false;
                    threadCircleRun.Abort();
                }
            }
            catch { }
        }
        Thread threadCircleRun = null;
        void ThreadCircleRun()
        {
            if (!isCircleRuning)
            {
                ProcessRunBll.LogInfo($"{ProcessRunBll.Name}关闭连续运行", LogInfoType.PASS);
                return;
            }
            ProcessRunBll.LogInfo($"{ProcessRunBll.Name}开启连续运行", LogInfoType.WARN);
            while (isCircleRuning)
            {
                //this.BeginInvoke(new Action(() =>
                //{
                try
                {
                    ProcessRunBll.LogInfo($"{ProcessRunBll.Name}开始运行", LogInfoType.WARN);
                    ClearObj();
                    bool result = ProcessRunBll.Run();
                    string msg = result ? "运行成功" : ProcessRunBll.Msg;
                    ProcessRunBll.LogInfo($"{ProcessRunBll.Name}运行结束,结果为:{msg}"
                        , result ? LogInfoType.PASS : LogInfoType.ERROR);
                    if (ProcessRunBll.GetImage(_Layout, out _, out HObject RecordImage))
                        ShowHoImage(RecordImage);
                }
                catch { }
                //}));
                Thread.Sleep(100);
            }
        }
        System.Windows.Forms.ToolTip TotalToolTip = new System.Windows.Forms.ToolTip();
        private void lblCount_DoubleClick(object sender, EventArgs e)
        {
            this.BeginInvoke(() =>
            {
                ProcessRunBll.ClearTotal();
                this.label1.Text = $"总数:{ProcessRunBll.total}";
            });
        }
        private void lblCount_MouseHover(object sender, EventArgs e)
        {
            // æ˜¾ç¤ºToolTip(相对于控件的位置)
            TotalToolTip.Show($"直通率:{ProcessRunBll.Rate_OK.ToString("F3")}", (Control)sender,
                               ((Control)sender).Width / 2, // x偏移
                               -20,                      // y偏移(负值表示上方)
                               2000);                    // æ˜¾ç¤ºæ—¶é—´(ms)
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessControl.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,123 @@
<?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>
  <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
    <value>17, 17</value>
  </metadata>
</root>
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,129 @@
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class ProcessInputsEditControl
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            lblInput = new Label();
            lbl = new Label();
            lblOutput = new Label();
            uiButtonEdit = new Button();
            tableLayoutPanel1.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 4;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.33333F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333359F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 33.3333359F));
            tableLayoutPanel1.Controls.Add(lblInput, 0, 0);
            tableLayoutPanel1.Controls.Add(lbl, 1, 0);
            tableLayoutPanel1.Controls.Add(lblOutput, 2, 0);
            tableLayoutPanel1.Controls.Add(uiButtonEdit, 3, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.ForeColor = SystemColors.Control;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 1;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(500, 50);
            tableLayoutPanel1.TabIndex = 0;
            //
            // lblInput
            //
            lblInput.AutoSize = true;
            lblInput.Dock = DockStyle.Fill;
            lblInput.Font = new Font("Microsoft YaHei UI", 12F);
            lblInput.Location = new Point(3, 0);
            lblInput.Name = "lblInput";
            lblInput.Size = new Size(153, 50);
            lblInput.TabIndex = 1;
            lblInput.Text = "X.Inputs.X";
            lblInput.TextAlign = ContentAlignment.MiddleRight;
            //
            // lbl
            //
            lbl.AutoSize = true;
            lbl.Dock = DockStyle.Fill;
            lbl.Font = new Font("Microsoft YaHei UI", 12F);
            lbl.Location = new Point(162, 0);
            lbl.Name = "lbl";
            lbl.Size = new Size(14, 50);
            lbl.TabIndex = 2;
            lbl.Text = "-";
            lbl.TextAlign = ContentAlignment.MiddleCenter;
            //
            // lblOutput
            //
            lblOutput.AutoSize = true;
            lblOutput.Dock = DockStyle.Fill;
            lblOutput.Font = new Font("Microsoft YaHei UI", 12F);
            lblOutput.Location = new Point(182, 0);
            lblOutput.Name = "lblOutput";
            lblOutput.Size = new Size(154, 50);
            lblOutput.TabIndex = 3;
            lblOutput.Text = "X.Outputs.X";
            lblOutput.TextAlign = ContentAlignment.MiddleLeft;
            //
            // uiButtonEdit
            //
            uiButtonEdit.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            uiButtonEdit.Location = new Point(342, 3);
            uiButtonEdit.MinimumSize = new Size(1, 1);
            uiButtonEdit.Name = "uiButtonEdit";
            uiButtonEdit.Size = new Size(75, 44);
            uiButtonEdit.TabIndex = 0;
            uiButtonEdit.Text = "编辑";
            uiButtonEdit.Click += uiButtonEdit_Click;
            //
            // ProcessInputsEditControl
            //
            AutoScaleDimensions = new SizeF(96F, 96F);
            AutoScaleMode = AutoScaleMode.Dpi;
            Controls.Add(tableLayoutPanel1);
            MaximumSize = new Size(1920, 50);
            MinimumSize = new Size(0, 50);
            Name = "ProcessInputsEditControl";
            Size = new Size(500, 50);
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel1.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private Button uiButtonEdit;
        public Label lblInput;
        private Label lbl;
        public Label lblOutput;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class ProcessInputsEditControl : UserControl
    {
        public ProcessInputsEditControl()
        {
            InitializeComponent();
        }
        public ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping { get; set; }
        public ConcurrentDictionary<string, List<string>> dicOutputsMapping { get; set; }
        public ProcessInputsEditControl(string strInput, string strOutput
            , ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping, ConcurrentDictionary<string, List<string>> dicOutputsMapping)
        {
            InitializeComponent();
            this.lblInput.Text = strInput;
            this.lblOutput.Text = strOutput;
            this.dicInputsMapping = dicInputsMapping;
            this.dicOutputsMapping = dicOutputsMapping;
        }
        private void uiButtonEdit_Click(object sender, EventArgs e)
        {
            string[] inputs = this.lblInput.Text.Split('.');
            ProcessOutputsSelectForm processOutputsSelectForm = new ProcessOutputsSelectForm(dicInputsMapping, dicOutputsMapping, inputs[0]);
            processOutputsSelectForm.ShowDialog();
            this.lblOutput.Text = processOutputsSelectForm.SelectedOutput;
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsEditControl.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,110 @@
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class ProcessInputsSelectForm
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProcessInputsSelectForm));
            themeForm1 = new ReaLTaiizor.Forms.ThemeForm();
            panel = new ReaLTaiizor.Controls.Panel();
            controlBox1 = new ReaLTaiizor.Controls.ControlBox();
            themeForm1.SuspendLayout();
            SuspendLayout();
            //
            // themeForm1
            //
            themeForm1.BackColor = Color.FromArgb(32, 41, 50);
            themeForm1.Controls.Add(controlBox1);
            themeForm1.Controls.Add(panel);
            themeForm1.Dock = DockStyle.Fill;
            themeForm1.Font = new Font("Microsoft Sans Serif", 9F);
            themeForm1.Image = (Image)resources.GetObject("themeForm1.Image");
            themeForm1.Location = new Point(0, 0);
            themeForm1.Name = "themeForm1";
            themeForm1.Padding = new Padding(10, 70, 10, 9);
            themeForm1.RoundCorners = true;
            themeForm1.Sizable = true;
            themeForm1.Size = new Size(907, 484);
            themeForm1.SmartBounds = true;
            themeForm1.StartPosition = FormStartPosition.WindowsDefaultLocation;
            themeForm1.TabIndex = 2;
            themeForm1.Text = "themeForm1";
            //
            // panel
            //
            panel.BackColor = Color.FromArgb(39, 51, 63);
            panel.Dock = DockStyle.Fill;
            panel.EdgeColor = Color.FromArgb(32, 41, 50);
            panel.Location = new Point(10, 70);
            panel.Name = "panel";
            panel.Padding = new Padding(5);
            panel.Size = new Size(887, 405);
            panel.SmoothingType = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            panel.TabIndex = 0;
            panel.Text = "panel1";
            //
            // controlBox1
            //
            controlBox1.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            controlBox1.BackColor = Color.FromArgb(32, 34, 37);
            controlBox1.CloseHoverColor = Color.FromArgb(230, 17, 35);
            controlBox1.DefaultLocation = true;
            controlBox1.EnableHoverHighlight = true;
            controlBox1.EnableMaximizeButton = true;
            controlBox1.EnableMinimizeButton = true;
            controlBox1.ForeColor = Color.FromArgb(155, 155, 155);
            controlBox1.Location = new Point(804, 12);
            controlBox1.MaximizeHoverColor = Color.FromArgb(74, 74, 74);
            controlBox1.MinimizeHoverColor = Color.FromArgb(63, 63, 65);
            controlBox1.Name = "controlBox1";
            controlBox1.Size = new Size(90, 25);
            controlBox1.TabIndex = 1;
            controlBox1.Text = "controlBox1";
            //
            // ProcessInputsSelectForm
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(907, 484);
            Controls.Add(themeForm1);
            FormBorderStyle = FormBorderStyle.None;
            MinimumSize = new Size(261, 61);
            Name = "ProcessInputsSelectForm";
            Text = "themeForm1";
            TransparencyKey = Color.Fuchsia;
            FormClosing += ProcessInputsSelectForm_FormClosing;
            themeForm1.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private Button uiButtonOK;
        private ReaLTaiizor.Forms.ThemeForm themeForm1;
        private ReaLTaiizor.Controls.Panel panel;
        private ReaLTaiizor.Controls.ControlBox controlBox1;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,96 @@
using LB_SmartVision.ProcessRun;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class ProcessInputsSelectForm : Form
    {
        List<ProcessInputsEditControl> listProcessInputsEditControl = new List<ProcessInputsEditControl>();
        ProcessRunBll ProcessRunBll { get; set; }
        public ProcessInputsSelectForm()
        {
            InitializeComponent();
        }
        public ProcessInputsSelectForm(string ProcessName, ProcessRunBll RunBll)
        {
            InitializeComponent();
            if (!RunBll.dicInputsMapping.ContainsKey(ProcessName))
                return;
            ProcessRunBll = RunBll;
            int index = 0;
            foreach (Tuple<string, string> tupleInputAndOutput in RunBll.dicInputsMapping[ProcessName])
            {
                string Input = tupleInputAndOutput.Item1;
                string Output = tupleInputAndOutput.Item2;
                ProcessInputsEditControl processInputsEditControl = new ProcessInputsEditControl(Input, Output, RunBll.dicInputsMapping, RunBll.dicOutputsMapping);
                listProcessInputsEditControl.Add(processInputsEditControl);
                this.panel.Controls.Add(processInputsEditControl);
                processInputsEditControl.Size = new System.Drawing.Size(panel.Width, 50);
                processInputsEditControl.Location = new System.Drawing.Point(0, processInputsEditControl.Size.Height * index);
                index++;
            }
        }
        private void panel_SizeChanged(object sender, EventArgs e)
        {
            int index = 0;
            foreach (var item in listProcessInputsEditControl)
            {
                item.Size = new System.Drawing.Size(panel.Width, 50);
                item.Location = new System.Drawing.Point(0, item.Size.Height * index);
                index++;
            }
        }
        private void ProcessInputsSelectForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (ProcessRunBll == null)
            {
                e.Cancel = false;  //确认关闭窗体
                return;
            }
            DialogResult res = MessageBox.Show("是否保存?", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);  //保存结果信息
            /// å‚æ•°1:显示文本,参数2:标题,参数3:按键类型,参数4:显示图标
            if (res != DialogResult.Yes && res != DialogResult.No)  //取消
            {
                e.Cancel = true;  //取消关闭窗体
                return;
            }
            if (res == DialogResult.Yes)  //保存
            {
                string ProcessName = this.Text;
                List<Tuple<string, string>> tupleInputAndOutput = new List<Tuple<string, string>>();
                foreach (var control in listProcessInputsEditControl)
                {
                    string strInput = control.lblInput.Text;
                    string strOutput = control.lblOutput.Text;
                    Tuple<string, string> tuple = Tuple.Create(strInput, strOutput);
                    tupleInputAndOutput.Add(tuple);
                }
                ProcessRunBll.dicInputsMapping.TryRemove(ProcessName, out _);
                ProcessRunBll.dicInputsMapping.TryAdd(ProcessName, tupleInputAndOutput);
                e.Cancel = false;  //确认关闭窗体
                return;
            }
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessInputsSelectForm.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,286 @@
<?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>
  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <data name="themeForm1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAIAAAB7GkOtAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
        YQUAACVUSURBVHhe7dXLDnD/OYbhb1RnQP1L5yZodRe7gUTsK6k2StJo42Boi3AE9gRnRChBgqGx4gCu
        +e/NnTwr12jNVlbe+/nw8z/8vWlf+dxHab/1kz+Y9tUvfCLNL2r58mc/SvvGT38y7Yuf+njaB5PaYlJb
        POkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkW
        k9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9ri
        F7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY
        1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT
        2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJS
        WzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYA
        xzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzp
        FpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa
        4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1
        mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQW
        k9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9pi
        Uls2AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2
        AMc86RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc8
        6RaT2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT
        2uIXtZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIX
        tZjUFpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjU
        FpPaYlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPa
        YlJbNgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJb
        NgDHPOkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbNgDH
        POkWk9riF7WY1BaT2mJSWzYAxzzpFpPa4he1mNQWk9piUls2AMc86RaT2uIXtZjUFpPaYlJbPnznz7+V
        9rWf+ME0T6LlF3/k+9K+/lOfTPuVT308zYto+c+//aO0DcAxk9piUltMaotJbfEiWkxqywbgmEltMakt
        JrXFpLZ4ES0mtWUDcMyktpjUFpPaYlJbvIgWk9qyAThmUltMaotJbTGpLV5Ei0lt2QAcM6ktJrXFpLaY
        1BYvosWktmwAjpnUFpPaYlJbTGqLF9FiUls2AMdMaotJbTGpLSa1xYtoMaktG4BjJrXFpLaY1BaT2uJF
        tJjUlg3AMZPaYlJbTGqLSW3xIlpMassG4JhJbTGpLSa1xaS2eBEtJrVlA3DMpLaY1BaT2mJSW7yIFpPa
        sgE4ZlJbTGqLSW0xqS1eRItJbdkAHDOpLSa1xaS2mNQWL6LFpLZsAI6Z1BaT2mJSW0xqixfRYlJbNgDH
        TGqLSW0xqS0mtcWLaDGpLRuAYya1xaS2mNQWk9riRbSY1JYNwDGT2mJSW0xqi0lt8SJaTGrLBuCYSW0x
        qS0mtcWktngRLSa1ZQNwzKS2mNQWk9piUlu8iBaT2rIBOGZSW0xqi0ltMaktXkSLSW3ZABwzqS0mtcWk
        tpjUFi+ixaS2bACOmdQWk9piUltMaosX0WJSWzYAx0xqi0ltMaktJrXFi2gxqS0bgGMmtcWktpjUFpPa
        4kW0mNSWDcAxk9piUltMaotJbfEiWkxqywbgmEltMaktJrXFpLZ4ES0mtWUDcMyktpjUFpPaYlJbvIgW
        k9qyAThmUltMaotJbTGpLV5Ei0lt2QAcM6ktJrXFpLaY1BYvosWktmwAjpnUFpPaYlJbTGqLF9FiUls2
        AMdMaotJbTGpLSa1xYtoMaktG4BjJrXFpLaY1BaT2uJFtJjUlg3AMZPaYlJbTGqLSW3xIlpMassG4JhJ
        bTGpLSa1xaS2eBEtJrVlA3DMpLaY1BaT2mJSW7yIFpPasgE4ZlJbTGqLSW0xqS1eRItJbdkAHDOpLSa1
        xaS2mNQWL6LFpLZsAI6Z1BaT2mJSW0xqixfRYlJbNgDHTGqLSW0xqS0mtcWLaDGpLRuAYya1xaS2mNQW
        k9riRbSY1JYNwDGT2mJSW0xqi0lt8SJaTGrLBuCYSW0xqS0mtcWktngRLSa1ZQNwzKS2mNQWk9piUlu8
        iBaT2rIBOGZSW0xqi0ltMaktXkSLSW3ZABwzqS0mtcWktpjUFi+ixaS2bACOmdQWk9piUltMaosX0WJS
        WzYAx0xqi0ltMaktJrXFi2gxqS0bgGMmtcWktpjUFpPa4kW0mNSWDcAxk9piUltMaotJbfEiWkxqywbg
        mEltMaktJrXFpLZ4ES0mtWUDcMyktpjUFpPaYlJbvIgWk9qyAThmUltMaotJbTGpLV5Ei0lt2QAcM6kt
        JrXFpLaY1BYvosWktmwAjpnUFpPaYlJbTGqLF9FiUls2AMdMaotJbTGpLSa1xYtoMaktG4BjJrXFpLaY
        1BaT2uJFtJjUlg3AMZPaYlJbTGqLSW3xIlpMassG4JhJbTGpLSa1xaS2eBEtJrVlA3DMpLaY1BaT2mJS
        W7yIFpPasgE4ZlJbTGqLSW0xqS1eRItJbdkAHDOpLSa1xaS2mNQWL6LFpLZsAI6Z1BaT2mJSW0xqixfR
        YlJbNgDHTGqLSW0xqS0mtcWLaDGpLR9+88d/IO1Ln/n+NE+ixUlo8aTnpV///CfSfuMLbRuAYya1xaS2
        mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qy
        AThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYlk9piUls2AMdMaotJbTFJ
        85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNw
        zKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYl
        k9piUls2AMdMaotJbTFJ85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJ
        bTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1
        xaS2bACOmdQWk9pikuYlk9piUls2AMdMaotJbTFJ85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9pi
        UltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJ
        bdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYlk9piUls2AMdMaotJbTFJ85JJbTGpLRuAYya1xaS2
        mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qy
        AThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYlk9piUls2AMdMaotJbTFJ
        85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNw
        zKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYl
        k9piUls2AMdMaotJbTFJ85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9piUltM0rxkUltMassG4JhJ
        bTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJbdkAHDOpLSa1xSTNSya1
        xaS2bACOmdQWk9pikuYlk9piUls2AMdMaotJbTFJ85JJbTGpLRuAYya1xaS2mKR5yaS2mNSWDcAxk9pi
        UltM0rxkUltMassG4JhJbTGpLSZpXjKpLSa1ZQNwzKS2mNQWkzQvmdQWk9qyAThmUltMaotJmpdMaotJ
        bdkAHDOpLSa1xSTNSya1xaS2bACOmdQWk9pikuYlk9piUls+/Otf/X7a/8WfH/rYx9L8Iy1//8e/k/aj
        3/M9af/73e+m/eff/mHaBuD4Makt/pEWk9piUltMaotJbdkAHD8mtcU/0mJSW0xqi0ltMaktG4Djx6S2
        +EdaTGqLSW0xqS0mtWUDcPyY1Bb/SItJbTGpLSa1xaS2bACOH5Pa4h9pMaktJrXFpLaY1JYNwPFjUlv8
        Iy0mtcWktpjUFpPasgE4fkxqi3+kxaS2mNQWk9piUls2AMePSW3xj7SY1BaT2mJSW0xqywbg+DGpLf6R
        FpPaYlJbTGqLSW3ZABw/JrXFP9JiUltMaotJbTGpLRuA48ektvhHWkxqi0ltMaktJrVlA3D8mNQW/0iL
        SW0xqS0mtcWktmwAjh+T2uIfaTGpLSa1xaS2mNSWDcDxY1Jb/CMtJrXFpLaY1BaT2rIBOH5Maot/pMWk
        tpjUFpPaYlJbNgDHj0lt8Y+0mNQWk9piUltMassG4PgxqS3+kRaT2mJSW0xqi0lt2QAcPya1xT/SYlJb
        TGqLSW0xqS0bgOPHpLb4R1pMaotJbTGpLSa1ZQNw/JjUFv9Ii0ltMaktJrXFpLZsAI4fk9riH2kxqS0m
        tcWktpjUlg3A8WNSW/wjLSa1xaS2mNQWk9qyATh+TGqLf6TFpLaY1BaT2mJSWzYAx49JbfGPtJjUFpPa
        YlJbTGrLBuD4Makt/pEWk9piUltMaotJbdkAHD8mtcU/0mJSW0xqi0ltMaktG4Djx6S2+EdaTGqLSW0x
        qS0mtWUDcPyY1Bb/SItJbTGpLSa1xaS2bACOH5Pa4h9pMaktJrXFpLaY1JYNwPFjUlv8Iy0mtcWktpjU
        FpPasgE4fkxqi3+kxaS2mNQWk9piUls2AMePSW3xj7SY1BaT2mJSW0xqywbg+DGpLf6RFpPaYlJbTGqL
        SW3ZABw/JrXFP9JiUltMaotJbTGpLRuA48ektvhHWkxqi0ltMaktJrVlA3D8mNQW/0iLSW0xqS0mtcWk
        tmwAjh+T2uIfaTGpLSa1xaS2mNSWDcDxY1Jb/CMtJrXFpLaY1BaT2rIBOH5Maot/pMWktpjUFpPaYlJb
        NgDHj0lt8Y+0mNQWk9piUltMassG4PgxqS3+kRaT2mJSW0xqi0lt2QAcPya1xT/SYlJbTGqLSW0xqS0b
        gOPHpLb4R1pMaotJbTGpLSa1ZQNw/JjUFv9Ii0ltMaktJrXFpLZsAI4fk9riH2kxqS0mtcWktpjUlg3A
        8WNSW/wjLSa1xaS2mNQWk9qyATh+TGqLf6TFpLaY1BaT2mJSWzYAx49JbfGPtJjUFpPaYlJbTGrLBuD4
        Makt/pEWk9piUltMaotJbdkAHD8mtcU/0mJSW0xqi0ltMaktG4Djx6S2+EdaTGqLSW0xqS0mtWUDcPyY
        1Bb/SItJbTGpLSa1xaS2bACOH5Pa4h9pMaktJrXFpLaY1JYNwPFjUlv8Iy0mtcWktpjUFpPasgE4fkxq
        i3+kxaS2mNQWk9piUls2AMePSW3xj7SY1BaT2mJSW0xqywbg+DGpLf6RFpPaYlJbTGqLSW3ZABw/JrXF
        P9JiUltMaotJbTGpLRuA48ektvhHWkxqi0ltMaktJrVlA3D8mNQW/0iLSW0xqS0mtcWktmwAjh+T2uIf
        aTGpLSa1xaS2mNSWDcDxY1Jb/CMtJrXFpLaY1BaT2rIBOH5Maot/pMWktpjUFpPaYlJbPviq5d/+9Jtp
        //Rn30r7r7/7o7R//+s/SPuXv/h22n/95e+l/cOf/G7aBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqL
        SW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWk
        tpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJb
        TGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0b
        gGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnU
        FpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqL
        SW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWk
        tpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJb
        TGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0b
        gGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnU
        FpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqL
        SW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWk
        tpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJb
        TGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0b
        gGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnU
        FpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqL
        SW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWk
        tpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJb
        TGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0b
        gGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnU
        FpPaYlJbTGqLSW0xqS0ffv3zn0j7xz/7Ztp3/vxbab/8qY+nfTHun//i22n/8Td/mPaVz32UtgE4ZlJb
        TGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0m
        tcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPa
        YlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0x
        qS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwA
        jpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJb
        TGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0m
        tcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPa
        YlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0x
        qS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwA
        jpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJb
        TGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0m
        tcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPa
        YlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0x
        qS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwA
        jpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJb
        TGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0m
        tcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPa
        YlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwAjpnUFpPaYlJbTGqLSW0x
        qS0bgGMmtcWktpjUFpPaYlJbTGrLBuCYSW0xqS0mtcWktpjUFpPasgE4ZlJbTGqLSW0xqS0mtcWktmwA
        jpnUFpPaYlJbTGqLSW0xqS0bgGMmtcWktpjUFpPaYlJbTGrLhy995vvT/KSWL3+27bv/899z6Euf+SjN
        i2j51U9/PG0DcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUD
        cMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmk
        tngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNw
        zKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2
        eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DM
        pLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4
        ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyk
        tpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngR
        LSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2
        mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEt
        JrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaY
        pHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0m
        tWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpik
        ecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1
        ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5
        yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVl
        A3DMpLaYpHnJpLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJ
        pLZ4ES0mtWUDcMyktpikecmktngRLSa1ZQNwzKS2mKR5yaS2eBEtJrVlA3DMpLaYpHnJpLZ4ES0mteXD
        N37hx9J++5c+k/a1n/1U2lc+94m0X/vsR2lf/7lPp331Z354Dm0AjpnUFpPaYlJbTGqLSZqXNgDHTGqL
        SW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpik
        eWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0xqS0maV7aABwzqS0mtcWktpjUFpM0L20AjpnUFpPa
        YlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPS
        BuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0xqS0maV7aABwzqS0mtcWk
        tpjUFpM0L20AjpnUFpPaYlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3A
        MZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0x
        qS0maV7aABwzqS0mtcWktpjUFpM0L20AjpnUFpPaYlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMm
        tcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJb
        TNK8tAE4ZlJbTGqLSW0xqS0maV7aABwzqS0mtcWktpjUFpM0L20AjpnUFpPaYlJbTGqLSZqXNgDHTGqL
        SW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpik
        eWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0xqS0maV7aABwzqS0mtcWktpjUFpM0L20AjpnUFpPa
        YlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPS
        BuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0xqS0maV7aABwzqS0mtcWk
        tpjUFpM0L20AjpnUFpPaYlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMmtcWktpjUFpPaYpLmpQ3A
        MZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJbTNK8tAE4ZlJbTGqLSW0x
        qS0maV7aABwzqS0mtcWktpjUFpM0L20AjpnUFpPaYlJbTGqLSZqXNgDHTGqLSW0xqS0mtcUkzUsbgGMm
        tcWktpjUFpPaYpLmpQ3AMZPaYlJbTGqLSW0xSfPSBuCYSW0xqS0mtcWktpikeWkDcMyktpjUFpPaYlJb
        TNK8tAE4ZlJbTGqLSW0xqS0maV76fzfth9drmQBzAAAAAElFTkSuQmCC
</value>
  </data>
</root>
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,132 @@
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class ProcessOutputsSelectForm
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            uiButtonOK = new Button();
            uiButtonCancel = new Button();
            treeViewOutputs = new TreeView();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Controls.Add(treeViewOutputs, 0, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(679, 496);
            tableLayoutPanel1.TabIndex = 0;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666718F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666679F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666679F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666679F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666679F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.6666679F));
            tableLayoutPanel2.Controls.Add(uiButtonOK, 4, 0);
            tableLayoutPanel2.Controls.Add(uiButtonCancel, 5, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 449);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(673, 44);
            tableLayoutPanel2.TabIndex = 0;
            //
            // uiButtonOK
            //
            uiButtonOK.Dock = DockStyle.Fill;
            uiButtonOK.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            uiButtonOK.ForeColor = SystemColors.Control;
            uiButtonOK.Location = new Point(451, 3);
            uiButtonOK.MinimumSize = new Size(1, 1);
            uiButtonOK.Name = "uiButtonOK";
            uiButtonOK.Size = new Size(106, 38);
            uiButtonOK.TabIndex = 0;
            uiButtonOK.Text = "确定";
            uiButtonOK.Click += uiButtonOK_Click;
            //
            // uiButtonCancel
            //
            uiButtonCancel.Dock = DockStyle.Fill;
            uiButtonCancel.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            uiButtonCancel.ForeColor = SystemColors.Control;
            uiButtonCancel.Location = new Point(563, 3);
            uiButtonCancel.MinimumSize = new Size(1, 1);
            uiButtonCancel.Name = "uiButtonCancel";
            uiButtonCancel.Size = new Size(107, 38);
            uiButtonCancel.TabIndex = 1;
            uiButtonCancel.Text = "取消";
            uiButtonCancel.Click += uiButtonCancel_Click;
            //
            // treeViewOutputs
            //
            treeViewOutputs.BackColor = Color.FromArgb(39, 51, 63);
            treeViewOutputs.Dock = DockStyle.Fill;
            treeViewOutputs.ForeColor = SystemColors.Control;
            treeViewOutputs.Location = new Point(3, 3);
            treeViewOutputs.Name = "treeViewOutputs";
            treeViewOutputs.Size = new Size(673, 440);
            treeViewOutputs.TabIndex = 1;
            //
            // ProcessOutputsSelectForm
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            BackColor = Color.FromArgb(39, 51, 63);
            ClientSize = new Size(679, 496);
            Controls.Add(tableLayoutPanel1);
            FormBorderStyle = FormBorderStyle.None;
            Name = "ProcessOutputsSelectForm";
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
        private TreeView treeViewOutputs;
        private Button uiButtonOK;
        private Button uiButtonCancel;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,102 @@
using LB_VisionProcesses;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class ProcessOutputsSelectForm : Form
    {
        public string SelectedOutput = string.Empty;
        public ProcessOutputsSelectForm()
        {
            InitializeComponent();
        }
        public ProcessOutputsSelectForm(ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping, ConcurrentDictionary<string, List<string>> dicOutputsMapping, string ProcessName = "")
        {
            InitializeComponent();
            treeViewOutputs.Nodes.Clear();
            // åˆ›å»ºçˆ¶èŠ‚ç‚¹
            TreeNode nullNode = new TreeNode("无");
            treeViewOutputs.Nodes.Add(nullNode);
            // åˆ›å»ºçˆ¶èŠ‚ç‚¹
            TreeNode globalNode = new TreeNode("全局变量");
            foreach (var name in IProcess.dicGlobalVars.Keys)
            {
                // åˆ›å»ºå­èŠ‚ç‚¹
                TreeNode childNode1 = new TreeNode(name);
                globalNode.Nodes.Add(childNode1);
            }
            treeViewOutputs.Nodes.Add(globalNode);
            foreach (var item in dicOutputsMapping)
            {
                if (ProcessName != item.Key)
                {
                    // åˆ›å»ºçˆ¶èŠ‚ç‚¹
                    TreeNode parentNode = new TreeNode(item.Key);
                    // æ·»åŠ è¾“å…¥èŠ‚ç‚¹
                    TreeNode InputsNode = new TreeNode("Inputs");
                    List<Tuple<string, string>> listInputs = dicInputsMapping[item.Key];
                    foreach (var inputs in listInputs)
                    {
                        // åˆ›å»ºå­èŠ‚ç‚¹
                        TreeNode childNode1 = new TreeNode(inputs.Item1);
                        InputsNode.Nodes.Add(childNode1);
                    }
                    // æ·»åŠ è¾“å‡ºèŠ‚ç‚¹
                    TreeNode OutputsNode = new TreeNode("Outputs");
                    List<string> listOutputs = item.Value;
                    foreach (var output in listOutputs)
                    {
                        // åˆ›å»ºå­èŠ‚ç‚¹
                        TreeNode childNode1 = new TreeNode(output);
                        OutputsNode.Nodes.Add(childNode1);
                    }
                    // å°†çˆ¶èŠ‚ç‚¹æ·»åŠ åˆ° TreeView
                    parentNode.Nodes.Add(InputsNode);
                    parentNode.Nodes.Add(OutputsNode);
                    treeViewOutputs.Nodes.Add(parentNode);
                }
            }
        }
        private void uiButtonOK_Click(object sender, EventArgs e)
        {
            if (this.treeViewOutputs.SelectedNode == null)
                return;
            if (this.treeViewOutputs.SelectedNode.Text == "无")
            {
                SelectedOutput = string.Empty;
                this.Close();
            }
            if (this.treeViewOutputs.SelectedNode.Parent != null)
            {
                SelectedOutput = this.treeViewOutputs.SelectedNode.Text;
                this.Close();
            }
        }
        private void uiButtonCancel_Click(object sender, EventArgs e)
        {
            SelectedOutput = string.Empty;
            this.Close();
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessOutputsSelectForm.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,149 @@
using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    partial class ProcessPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            btn_Run = new HopeButton();
            tableLayoutPanel3 = new TableLayoutPanel();
            tableLayoutPanel4 = new TableLayoutPanel();
            panel1 = new System.Windows.Forms.Panel();
            splitContainer1 = new SplitContainer();
            tableLayoutPanel3.SuspendLayout();
            tableLayoutPanel4.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
            splitContainer1.Panel2.SuspendLayout();
            splitContainer1.SuspendLayout();
            SuspendLayout();
            //
            // btn_Run
            //
            btn_Run.BorderColor = Color.FromArgb(220, 223, 230);
            btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btn_Run.DangerColor = Color.FromArgb(245, 108, 108);
            btn_Run.DefaultColor = Color.FromArgb(255, 255, 255);
            btn_Run.Dock = DockStyle.Fill;
            btn_Run.Font = new Font("宋体", 12F);
            btn_Run.HoverTextColor = Color.FromArgb(48, 49, 51);
            btn_Run.InfoColor = Color.FromArgb(144, 147, 153);
            btn_Run.Location = new Point(419, 3);
            btn_Run.MinimumSize = new Size(1, 1);
            btn_Run.Name = "btn_Run";
            btn_Run.PrimaryColor = Color.FromArgb(64, 158, 255);
            btn_Run.Size = new Size(102, 38);
            btn_Run.SuccessColor = Color.FromArgb(103, 194, 58);
            btn_Run.TabIndex = 1;
            btn_Run.Text = "运行";
            btn_Run.TextColor = Color.White;
            btn_Run.WarningColor = Color.FromArgb(230, 162, 60);
            btn_Run.Click += btn_Run_Click;
            //
            // tableLayoutPanel3
            //
            tableLayoutPanel3.ColumnCount = 1;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Controls.Add(tableLayoutPanel4, 0, 1);
            tableLayoutPanel3.Controls.Add(panel1, 0, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(0, 0);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 2;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel3.Size = new Size(530, 371);
            tableLayoutPanel3.TabIndex = 10;
            //
            // tableLayoutPanel4
            //
            tableLayoutPanel4.ColumnCount = 5;
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
            tableLayoutPanel4.Controls.Add(btn_Run, 4, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(3, 324);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
            tableLayoutPanel4.RowCount = 1;
            tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Size = new Size(524, 44);
            tableLayoutPanel4.TabIndex = 0;
            //
            // panel1
            //
            panel1.AutoScroll = true;
            panel1.Dock = DockStyle.Fill;
            panel1.ForeColor = SystemColors.Control;
            panel1.Location = new Point(3, 3);
            panel1.Name = "panel1";
            panel1.Size = new Size(524, 315);
            panel1.TabIndex = 1;
            //
            // splitContainer1
            //
            splitContainer1.Dock = DockStyle.Fill;
            splitContainer1.Location = new Point(0, 0);
            splitContainer1.Name = "splitContainer1";
            //
            // splitContainer1.Panel1
            //
            splitContainer1.Panel1.ForeColor = SystemColors.Control;
            //
            // splitContainer1.Panel2
            //
            splitContainer1.Panel2.Controls.Add(tableLayoutPanel3);
            splitContainer1.Size = new Size(801, 371);
            splitContainer1.SplitterDistance = 267;
            splitContainer1.TabIndex = 11;
            //
            // ProcessPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(splitContainer1);
            Name = "ProcessPage";
            Size = new Size(801, 371);
            Paint += ProcessPage_Paint;
            tableLayoutPanel3.ResumeLayout(false);
            tableLayoutPanel4.ResumeLayout(false);
            splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
            splitContainer1.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton btn_Run;
        //private Light uiLight1;
        private TableLayoutPanel tableLayoutPanel3;
        private TableLayoutPanel tableLayoutPanel4;
        private SplitContainer splitContainer1;
        private System.Windows.Forms.Panel panel1;
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,404 @@
using HalconDotNet;
using OpenCvSharp;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Collections.Concurrent;
using LB_VisionControl;
using LB_SmartVision.ProcessRun;
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
namespace LB_SmartVision.Forms.Pages.ProcessPage
{
    public partial class ProcessPage : UserControl
    {
        /// <summary>
        /// è¿è¡Œæ­¥éª¤(object为IProces或者object为ICamera)
        /// </summary>
        public ProcessRunBll ProcessRunBll { get; set; }
        public Action<string, LogInfoType> LogInfo;
        private UserHSmartWindowControl UserHSmartWindowControl = new UserHSmartWindowControl();
        public ProcessPage()
        {
            InitializeComponent();
        }
        public ProcessPage(string Name, ProcessRunBll ProcessRunBll)
        {
            InitializeComponent();
            this.Text = "ProcessPage";
            this.Name = Name;
            this.ProcessRunBll = ProcessRunBll;
            Name = ProcessRunBll.Name;
            Text = ProcessRunBll.Name;
            this.splitContainer1.Panel1.Controls.Add(UserHSmartWindowControl);
            UserHSmartWindowControl.Dock = DockStyle.Fill;
            this.panel1.Controls.Add(ProcessRunBll.nodesControl);
            ProcessRunBll.nodesControl.Location = new System.Drawing.Point(0, 0);
            ProcessRunBll.nodesControl.Size = new System.Drawing.Size(5000, 5000);
            RemoveAllHandler();
            ProcessRunBll.nodesControl.AddNodeAction += AddProcess;
            ProcessRunBll.nodesControl.RenameNodeAction += RenameProcess;
            ProcessRunBll.nodesControl.InAndOutNodeAction += InAndOutProcess;
            ProcessRunBll.nodesControl.DeleteNodeAction += DeleteProcess;
            ProcessRunBll.nodesControl.EditNodeAction += EditProcess;
            ProcessRunBll.nodesControl.AddBranchAction += AddBranch;
            ProcessRunBll.nodesControl.DeleteBranchAction += DeleteBranch;
        }
        private void ProcessPage_Paint(object sender, PaintEventArgs e)
        {
            if (ProcessRunBll.Result)
                btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Success;
            else
                btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Danger;
            if (ProcessRunBll.GetImage(out _, out HObject RecordImage))
                UserHSmartWindowControl.ShowHoImage(RecordImage);
        }
        public void RemoveAllHandler()
        {
            ProcessRunBll.nodesControl.AddNodeAction -= AddProcess;
            ProcessRunBll.nodesControl.RenameNodeAction -= RenameProcess;
            ProcessRunBll.nodesControl.InAndOutNodeAction -= InAndOutProcess;
            ProcessRunBll.nodesControl.DeleteNodeAction -= DeleteProcess;
            ProcessRunBll.nodesControl.EditNodeAction -= EditProcess;
            ProcessRunBll.nodesControl.AddBranchAction -= AddBranch;
            ProcessRunBll.nodesControl.DeleteBranchAction -= DeleteBranch;
        }
        private void btn_Run_Click(object sender, EventArgs e)
        {
            this.BeginInvoke(new Action(() =>
            {
                UserHSmartWindowControl.ClearObj();
                LogInfo?.Invoke(string.Format("流程[{0}]开始运行", this.ProcessRunBll.Name), LogInfoType.INFO);
                bool result = this.ProcessRunBll.Run();
                string msg = ProcessRunBll.Msg;
                LogInfo?.Invoke(string.Format("流程[{0}]运行完成,结果:{1}", this.ProcessRunBll.Name, msg)
                    , result ? LogInfoType.PASS : LogInfoType.ERROR);
                if (ProcessRunBll.GetImage(out _, out HObject RecordImage))
                    UserHSmartWindowControl.ShowHoImage(RecordImage);
                if (result)
                    btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Success;
                else
                    btn_Run.ButtonType = ReaLTaiizor.Util.HopeButtonType.Danger;
            }));
        }
        public void AddProcess(string ProcessName, string Descript)
        {
            string ClassName = ProcessRunBll.Node2ToolClassName(Descript);
            string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
            if (ProcessRunBll.AddStep(ProcessRunBll.Name, ProcessName, ClassName, ProcessPath))
            {
                ProcessRunBll.SaveInputs();
                ProcessRunBll.SaveOutputs();
                ProcessRunBll.CompileMappings();
            }
            else
                LogInfo?.Invoke(string.Format("流程[{0}]添加步骤\"{1}\"失败", this.Text, ProcessName), LogInfoType.ERROR);
        }
        private void InAndOutProcess(string ProcessName)
        {
            var dicSteps = ProcessRunBll.GetSteps();
            if (!dicSteps.ContainsKey(ProcessName))
                return;
            ProcessInputsSelectForm inputsSelectForm = new ProcessInputsSelectForm(ProcessName, ProcessRunBll);
            inputsSelectForm.Text = ProcessName;
            inputsSelectForm.ShowDialog();
            ProcessRunBll.SaveInputs();
            ProcessRunBll.SaveOutputs();
            ProcessRunBll.CompileMappings();
            //string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
            //((IProcess)dicSteps[ProcessName]).Load(ProcessPath);
        }
        public void DeleteProcess(string ProcessName)
        {
            try
            {
                var dicSteps = ProcessRunBll.GetSteps();
                if (!dicSteps.ContainsKey(ProcessName))
                    return;
                string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
                if (string.IsNullOrEmpty(ProcessName) || string.IsNullOrEmpty(ProcessPath))
                    return;
                // èŽ·å–æ‰€æœ‰æ–‡ä»¶ï¼ˆä¸ç®¡åŽç¼€åæ˜¯ä»€ä¹ˆï¼‰å¹¶è¿›è¡ŒéåŽ†
                string directoryPath = Path.GetDirectoryName(ProcessPath);
                string[] files = Directory.GetFiles(directoryPath, ProcessName + ".*");  // åŒ¹é…æ‰€æœ‰åç§°ä¸ºaa的文件,后缀不限
                foreach (var file in files)
                {
                    try
                    {
                        if (File.Exists(file))
                            File.Delete(file);
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"删除文件 {file} æ—¶å‡ºé”™: {ex.Message}");
                        LogInfo?.Invoke(string.Format("流程[{0}]移除步骤\"{1}\"失败,原因是{2}", this.Text, ProcessName, ex.Message), LogInfoType.ERROR);
                        return;
                    }
                }
                if (Directory.Exists(directoryPath + "\\" + ProcessName))
                    Directory.Delete(directoryPath + "\\" + ProcessName, true);
                if (!ProcessRunBll.Remove(ProcessName))
                    LogInfo?.Invoke(string.Format("流程[{0}]移除步骤\"{1}\"失败", this.Text, ProcessName), LogInfoType.ERROR);
            }
            catch (Exception ex) { Debug.WriteLine(ex.Message); }
        }
        private void RenameProcess(string ProcessName, string newProcessName)
        {
            ConcurrentDictionary<string, IProcess> dicSteps = ProcessRunBll.GetSteps();
            if (!dicSteps.ContainsKey(ProcessName))
                return;
            ProcessRenameEvent(ProcessName, newProcessName);
        }
        private void ProcessRenameEvent(string oriName, string newName)
        {
            ConcurrentDictionary<string, IProcess> dicSteps = ProcessRunBll.GetSteps();
            //更新后的步骤名仍然需要是唯一
            if (dicSteps.ContainsKey(newName))
            {
                MessageBox.Show(string.Format("重命名失败,步骤名称[{0}]已存在!", newName), "异常");
                return;
            }
            if (dicSteps.ContainsKey(oriName))
            {
                string oriPath = GlobalVar.allProcessPath + this.Text + "\\" + oriName + ".json";
                string newPath = GlobalVar.allProcessPath + this.Text + "\\" + newName + ".json";
                string directoryPath = Path.GetDirectoryName(oriPath);
                string[] files = new string[] { };
                // é‡å‘½åå½“前文件夹
                files = Directory.GetFiles(directoryPath, oriName + ".*");  // åŒ¹é…æ‰€æœ‰åç§°ä¸ºoriName的文件,后缀不限
                foreach (var file in files)
                {
                    try
                    {
                        // èŽ·å–æ–‡ä»¶çš„æ‰©å±•å
                        string extension = Path.GetExtension(file);
                        // æž„造新文件名
                        string newFileName = Path.Combine(directoryPath, newName + extension);
                        if (!File.Exists(newFileName))
                        {
                            // é‡å‘½åæ–‡ä»¶
                            File.Move(file, newFileName);
                            Debug.WriteLine($"文件已重命名: {file} -> {newFileName}");
                        }
                        else
                        {
                            LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, "命名重复"), LogInfoType.ERROR);
                            return;
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"重命名文件 {file} æ—¶å‡ºé”™: {ex.Message}");
                        LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, ex.Message), LogInfoType.ERROR);
                        return;
                    }
                }
                // é‡å‘½åå½“前文件夹
                if (Directory.Exists(directoryPath + "\\" + oriName))
                {
                    Directory.Move(directoryPath + "\\" + oriName, directoryPath + "\\" + newName);
                    // é‡å‘½åå­æ–‡ä»¶å¤¹
                    string newParentDirectory = Path.GetDirectoryName(GlobalVar.allProcessPath + this.Text + "\\" + newName + "\\" + oriName + ".json");
                    files = Directory.GetFiles(newParentDirectory, oriName + ".*");  // åŒ¹é…å­æ–‡ä»¶å¤¹å†…所有名称为oriName的文件,后缀不限(一般只有一个)
                    foreach (var file in files)
                    {
                        try
                        {
                            // èŽ·å–æ–‡ä»¶çš„æ‰©å±•å
                            string extension = Path.GetExtension(file);
                            // æž„造新文件名
                            string newFileName = Path.Combine(newParentDirectory, newName + extension);
                            if (!File.Exists(newFileName))
                            {
                                if (!Directory.Exists(newParentDirectory))
                                    Directory.CreateDirectory(newParentDirectory);
                                // é‡å‘½åæ–‡ä»¶
                                File.Move(file, newFileName);
                                Debug.WriteLine($"文件已重命名: {file} -> {newFileName}");
                            }
                            else
                            {
                                LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, "命名重复"), LogInfoType.ERROR);
                                return;
                            }
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine($"重命名文件 {file} æ—¶å‡ºé”™: {ex.Message}");
                            LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"失败,原因是{3}", this.Text, oriName, newName, ex.Message), LogInfoType.ERROR);
                            return;
                        }
                    }
                }
                ProcessRunBll.Rename(oriName, newName);
                LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤\"{1}\"为\"{2}\"成功", this.Text, oriName, newName), LogInfoType.PASS);
                //if (dicSteps[newName] is VisionProTool && Tool.ContainsChinese(newName))
                //    MessageBox.Show($"VisionPro工具不支持命名为中文:{newName}", "异常");
            }
        }
        private void EditProcess(string ProcessName)
        {
            try
            {
                ConcurrentDictionary<string, IProcess> dicSteps = ProcessRunBll.GetSteps();
                if (!dicSteps.ContainsKey(ProcessName))
                    return;
                string ClassName = dicSteps[ProcessName].GetType().ToString();
                string ProcessPath = GlobalVar.allProcessPath + ProcessRunBll.Name + "\\" + ProcessName + ".json";
                if (string.IsNullOrEmpty(ProcessName) || string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(ProcessPath))
                    return;
                //利用反射创建实例
                Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
                if (type == null)
                {
                    LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"打开失败了,ç±»[{2}]不存在", this.Text, ProcessName, ClassName), LogInfoType.ERROR);
                    return;
                }
                IProcess process = ((IProcess)dicSteps[ProcessName]).Clone() as IProcess;
                Object InputImage = new Object();
                if (process.InputImage != null)
                {
                    if (process.InputImage is HObject ho_image && ho_image.IsInitialized())
                        InputImage = ho_image.CopyObj(1, -1);
                    else if (process.InputImage is Mat mat && !mat.Empty())
                        InputImage = mat.Clone();
                    else if (process.InputImage is Bitmap bitmap)
                        InputImage = bitmap.Clone();
                }
                if (ClassName.Contains("CameraConfig") && process is CameraConfig)
                {
                    LB_VisionProcesses.Cameras.CameraForm cameraForm
                        = new LB_VisionProcesses.Cameras.CameraForm(GlobalVar.dicCameras.Items, (CameraConfig)process, ProcessPath);
                    cameraForm.ShowDialog();
                    if (!(process.Load(ProcessPath)))
                        LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
                    process.strProcessName = ProcessName;
                }
                else if (ClassName.Contains("CommunicatorConfig") && process is CommunicatorConfig)
                {
                    LB_VisionProcesses.Communicators.CommunicatorForm communicatorForm
                        = new LB_VisionProcesses.Communicators.CommunicatorForm(GlobalVar.dicCommunicators.Items, (CommunicatorConfig)process, ProcessPath);
                    communicatorForm.ShowDialog();
                    if (!(process.Load(ProcessPath)))
                        LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
                    process.strProcessName = ProcessName;
                }
                else
                {
                    ProcessEditForm processEditForm = new ProcessEditForm(process, ProcessPath);
                    processEditForm.ShowDialog();
                    //重新加载更新后的步骤
                    if (processEditForm.hasChanged)
                        LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"更新了", this.Text, ProcessName), LogInfoType.WARN);
                    if (!(process.Load(ProcessPath)))
                        LogInfo?.Invoke(string.Format("流程[{0}]步骤\"{1}\"加载失败了", this.Text, ProcessName), LogInfoType.ERROR);
                    process.strProcessName = ProcessName;
                }
                if (InputImage != null)
                {
                    if (InputImage is HObject ho_image && ho_image.IsInitialized())
                        process.InputImage = ho_image.CopyObj(1, -1);
                    else if (InputImage is Mat mat && !mat.Empty())
                        process.InputImage = mat.Clone();
                    else if (InputImage is Bitmap bitmap)
                        process.InputImage = bitmap.Clone();
                }
                dicSteps[ProcessName] = process;
                ProcessRunBll.UpdataInputsAndOutputs(ProcessName, process);
            }
            catch (Exception ex) { Debug.WriteLine(ex.Message); }
        }
        private void AddBranch(string ProcessName)
        {
            var dicSteps = ProcessRunBll.GetSteps();
            if (!dicSteps.ContainsKey(ProcessName))
                return;
            // å¤šåˆ†æ”¯çš„æœ¬è´¨ä¸ºè„šæœ¬å·¥å…·,根据branchIndex来走对应的分支
            if (dicSteps[ProcessName] is LB_VisionProcesses.Processes.ScriptTool.ScriptTool ScriptTool)
            {
                ScriptTool.Params.Outputs.Add($"Branch{ScriptTool.Params.Outputs.Count}", false);
                Debug.WriteLine($"脚本工具[{ProcessName}]增加了Branch{ScriptTool.Params.Outputs.Count - 1}");
            }
        }
        private void DeleteBranch(string ProcessName)
        {
            var dicSteps = ProcessRunBll.GetSteps();
            if (!dicSteps.ContainsKey(ProcessName))
                return;
            // å¤šåˆ†æ”¯çš„æœ¬è´¨ä¸ºè„šæœ¬å·¥å…·,根据branchIndex来走对应的分支
            if (dicSteps[ProcessName] is LB_VisionProcesses.Processes.ScriptTool.ScriptTool ScriptTool
                && ScriptTool.Params.Outputs.Remove($"Branch{ScriptTool.Params.Outputs.Count}"))
            {
                Debug.WriteLine($"脚本工具[{ProcessName}]移除了Branch{ScriptTool.Params.Outputs.Count + 1}");
            }
        }
    }
}
LB_SmartVision/Forms/Pages/ProcessPage/ProcessPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/ControlStateManager.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    // æœ€ä¼˜æ–¹æ¡ˆå®žçް
    public class ControlStateManager
    {
        private readonly Dictionary<string, Control> _controlMap = new Dictionary<string, Control>();
        private readonly TableLayoutPanel _tablePanel;
        public ControlStateManager(TableLayoutPanel tablePanel)
        {
            _tablePanel = tablePanel;
            BuildControlMap();
        }
        // åˆå§‹åŒ–时构建控件字典(只需一次)
        private void BuildControlMap(Control parent = null)
        {
            parent = parent ?? _tablePanel;
            foreach (Control control in parent.Controls)
            {
                if (!string.IsNullOrEmpty(control.Name))
                {
                    _controlMap[control.Name] = control;
                }
                if (control.HasChildren)
                {
                    BuildControlMap(control);
                }
            }
        }
        // O(1) å¿«é€Ÿè®¿é—®
        public T GetControl<T>(string name) where T : Control
        {
            return _controlMap.TryGetValue(name, out Control control) ? control as T : null;
        }
        // èŽ·å–TextBox值
        public string GetTextBoxValue(string name)
        {
            return GetControl<TextBox>(name)?.Text;
        }
        // èŽ·å–CheckBox状态
        public bool? GetCheckBoxState(string name)
        {
            return GetControl<CheckBox>(name)?.Checked;
        }
        /// <summary>
        /// èŽ·å– ComboBox çš„选中项文本
        /// </summary>
        public string GetComboBoxText(string comboBoxName)
        {
            var comboBox = GetControl<ComboBox>(comboBoxName);
            return comboBox?.SelectedItem?.ToString() ?? string.Empty;
        }
        /// <summary>
        /// èŽ·å– ComboBox çš„选中索引
        /// </summary>
        public int GetComboBoxSelectedIndex(string comboBoxName)
        {
            var comboBox = GetControl<ComboBox>(comboBoxName);
            return comboBox?.SelectedIndex ?? -1;
        }
        /// <summary>
        /// èŽ·å– ComboBox çš„æ‰€æœ‰é¡¹
        /// </summary>
        public List<object> GetComboBoxItems(string comboBoxName)
        {
            var comboBox = GetControl<ComboBox>(comboBoxName);
            return comboBox?.Items.Cast<object>().ToList() ?? new List<object>();
        }
        /// <summary>
        /// èŽ·å– ComboBox çš„完整状态
        /// </summary>
        public ComboBoxState GetComboBoxState(string comboBoxName)
        {
            var comboBox = GetControl<ComboBox>(comboBoxName);
            if (comboBox == null) return null;
            return new ComboBoxState
            {
                Items = comboBox.Items.Cast<object>().ToList(),
                SelectedIndex = comboBox.SelectedIndex,
                SelectedItem = comboBox.SelectedItem,
                Text = comboBox.Text
            };
        }
        // åŠ¨æ€æ›´æ–°æŽ§ä»¶æ˜ å°„ï¼ˆå½“æ·»åŠ /删除控件时调用)
        public void RefreshControlMap()
        {
            _controlMap.Clear();
            BuildControlMap();
        }
    }
    // ComboBox çŠ¶æ€æ•°æ®ç»“æž„
    public class ComboBoxState
    {
        public List<object> Items { get; set; }
        public int SelectedIndex { get; set; }
        public object SelectedItem { get; set; }
        public string Text { get; set; }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,250 @@
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class CsvPage
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel3 = new TableLayoutPanel();
            btn_Add = new ReaLTaiizor.Controls.ForeverButton();
            btnDel = new ReaLTaiizor.Controls.AirButton();
            btn_Save = new ReaLTaiizor.Controls.HopeButton();
            tableLayoutPanel2 = new TableLayoutPanel();
            pnlLayout = new Panel();
            tableLayoutPanel4 = new TableLayoutPanel();
            label2 = new Label();
            label1 = new Label();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel3.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            tableLayoutPanel4.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(tableLayoutPanel3, 0, 1);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(772, 535);
            tableLayoutPanel1.TabIndex = 0;
            //
            // tableLayoutPanel3
            //
            tableLayoutPanel3.ColumnCount = 6;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.Controls.Add(btn_Add, 5, 0);
            tableLayoutPanel3.Controls.Add(btnDel, 0, 0);
            tableLayoutPanel3.Controls.Add(btn_Save, 4, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 488);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 1;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Size = new Size(766, 44);
            tableLayoutPanel3.TabIndex = 2;
            //
            // btn_Add
            //
            btn_Add.BackColor = Color.Transparent;
            btn_Add.BaseColor = Color.FromArgb(35, 168, 109);
            btn_Add.Dock = DockStyle.Fill;
            btn_Add.Font = new Font("宋体", 12F);
            btn_Add.Location = new Point(638, 3);
            btn_Add.MinimumSize = new Size(1, 1);
            btn_Add.Name = "btn_Add";
            btn_Add.Rounded = false;
            btn_Add.Size = new Size(125, 38);
            btn_Add.TabIndex = 3;
            btn_Add.Text = "添加";
            btn_Add.TextColor = Color.FromArgb(243, 243, 243);
            btn_Add.Click += btnAdd_Click;
            //
            // btnDel
            //
            btnDel.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            btnDel.Dock = DockStyle.Fill;
            btnDel.Font = new Font("Segoe UI", 9F);
            btnDel.Image = null;
            btnDel.Location = new Point(3, 3);
            btnDel.Name = "btnDel";
            btnDel.NoRounding = false;
            btnDel.Size = new Size(121, 38);
            btnDel.TabIndex = 5;
            btnDel.Text = "移除";
            btnDel.Transparent = false;
            //
            // btn_Save
            //
            btn_Save.BorderColor = Color.FromArgb(220, 223, 230);
            btn_Save.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btn_Save.DangerColor = Color.FromArgb(245, 108, 108);
            btn_Save.DefaultColor = Color.FromArgb(255, 255, 255);
            btn_Save.Dock = DockStyle.Fill;
            btn_Save.Font = new Font("Segoe UI", 12F);
            btn_Save.HoverTextColor = Color.FromArgb(48, 49, 51);
            btn_Save.InfoColor = Color.FromArgb(144, 147, 153);
            btn_Save.Location = new Point(511, 3);
            btn_Save.Name = "btn_Save";
            btn_Save.PrimaryColor = Color.FromArgb(64, 158, 255);
            btn_Save.Size = new Size(121, 38);
            btn_Save.SuccessColor = Color.FromArgb(103, 194, 58);
            btn_Save.TabIndex = 6;
            btn_Save.Text = "保存";
            btn_Save.TextColor = Color.White;
            btn_Save.WarningColor = Color.FromArgb(230, 162, 60);
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 1;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Controls.Add(pnlLayout, 0, 1);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel4, 0, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(2, 2);
            tableLayoutPanel2.Margin = new Padding(2);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 2;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 24F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(768, 481);
            tableLayoutPanel2.TabIndex = 6;
            //
            // pnlLayout
            //
            pnlLayout.Dock = DockStyle.Fill;
            pnlLayout.Location = new Point(3, 27);
            pnlLayout.Name = "pnlLayout";
            pnlLayout.Size = new Size(762, 451);
            pnlLayout.TabIndex = 3;
            //
            // tableLayoutPanel4
            //
            tableLayoutPanel4.ColumnCount = 2;
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 147F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel4.Controls.Add(label2, 0, 0);
            tableLayoutPanel4.Controls.Add(label1, 0, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(2, 2);
            tableLayoutPanel4.Margin = new Padding(2);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
            tableLayoutPanel4.RowCount = 1;
            tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Size = new Size(764, 20);
            tableLayoutPanel4.TabIndex = 4;
            //
            // label2
            //
            label2.AutoSize = true;
            label2.Dock = DockStyle.Fill;
            label2.ForeColor = SystemColors.Control;
            label2.Location = new Point(149, 0);
            label2.Margin = new Padding(2, 0, 2, 0);
            label2.Name = "label2";
            label2.Size = new Size(613, 20);
            label2.TabIndex = 10;
            label2.Text = "数据";
            label2.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label1
            //
            label1.AutoSize = true;
            label1.Dock = DockStyle.Fill;
            label1.ForeColor = SystemColors.Control;
            label1.Location = new Point(2, 0);
            label1.Margin = new Padding(2, 0, 2, 0);
            label1.Name = "label1";
            label1.Size = new Size(143, 20);
            label1.TabIndex = 8;
            label1.Text = "关联流程";
            label1.TextAlign = ContentAlignment.MiddleCenter;
            //
            // CsvPage
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(tableLayoutPanel1);
            Name = "CsvPage";
            Size = new Size(772, 535);
            SizeChanged += CsvPage_SizeChanged;
            Paint += CsvPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel3.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            tableLayoutPanel4.ResumeLayout(false);
            tableLayoutPanel4.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel3;
        private ReaLTaiizor.Controls.ForeverButton btn_Add;
        private Panel pnlLayout;
        private TableLayoutPanel tableLayoutPanel2;
        private TableLayoutPanel tableLayoutPanel4;
        private Label label1;
        private Label label2;
        private Label label6;
        private Label label5;
        private Label label4;
        private Label label3;
        private Label label7;
        private Label label13;
        private Label label12;
        private Label label11;
        private Label label10;
        private Label label8;
        private ReaLTaiizor.Controls.AirButton btnDel;
        private ReaLTaiizor.Controls.HopeButton btn_Save;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
using LB_VisionProcesses;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class CsvPage : UserControl
    {
        public CsvPage()
        {
            InitializeComponent();
            btn_Save.Click += (sender, e) =>
            {
                if (!VisionForm.SaveAllCsv())
                    MessageBox.Show("!!!保存失败!!!", "异常");
                else
                    MessageBox.Show("保存成功!");
            };
            btnDel.Click += (sender, e) =>
            {
                foreach (var control in pnlLayout.Controls)
                {
                    if (control is CsvSettingControl csvSettingControl
                        && csvSettingControl.IsSelected)
                    {
                        var item = GlobalVar.dicLayout.FirstOrDefault(x => x.Value.Title == csvSettingControl.Title);
                        GlobalVar.dicLayout.TryRemove(item.Key, out _);
                    }
                }
                this.Invalidate();
            };
        }
        private void CsvPage_Paint(object sender, PaintEventArgs e)
        {
            //this.pnlLayout.Controls.Clear();
            //var sortedKeys = GlobalVar.dicCsvSetting.Keys
            //    .OrderBy(k => k, new NaturalStringComparer())
            //    .ToList();
            //int index = 0;
            //foreach (var key in sortedKeys)
            //{
            //    string ProcessesName = key;
            //    CsvSettingControl control = new CsvSettingControl(GlobalVar.dicCsvSetting[ProcessesName]);
            //    control.Size = new Size(this.pnlLayout.Size.Width, control.Size.Height);
            //    control.Location = new Point(0, control.Size.Height * index);
            //    this.pnlLayout.Controls.Add(control);
            //    index++;
            //}
        }
        private void CsvPage_SizeChanged(object sender, EventArgs e) => CsvPage_VisibleChanged(sender, e);
        private void CsvPage_VisibleChanged(object sender, EventArgs e)
        {
            this.pnlLayout.Controls.Clear();
            var sortedKeys = GlobalVar.dicCsvSetting.Keys
                .OrderBy(k => k, new NaturalStringComparer())
                .ToList();
            int index = 0;
            foreach (var key in sortedKeys)
            {
                string ProcessesName = key;
                CsvSettingControl control = new CsvSettingControl(GlobalVar.dicCsvSetting[ProcessesName]);
                control.Size = new Size(this.pnlLayout.Size.Width, control.Size.Height);
                control.Location = new Point(0, control.Size.Height * index);
                this.pnlLayout.Controls.Add(control);
                index++;
            }
        }
        private void btnAdd_Click(object sender, EventArgs e)
        {
            GlobalVar.dicCsvSetting.TryAdd($"{GlobalVar.dicCsvSetting.Count}", new CsvSetting());
            CsvPage_VisibleChanged(sender, e);
        }
    }
    [Serializable]
    public class CsvSetting
    {
        public string ProcessName { get; set; } = string.Empty;
        public List<string> Others { get; set; } = new List<string>();
        public CsvSetting() { }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/CsvPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,122 @@
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class CsvSettingControl
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            btn_DelMsg = new Button();
            btn_AddMsg = new Button();
            cmb_Process = new ComboBox();
            ckb_Selected = new CheckBox();
            tableLayoutPanel1.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 5;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(btn_DelMsg, 3, 0);
            tableLayoutPanel1.Controls.Add(btn_AddMsg, 2, 0);
            tableLayoutPanel1.Controls.Add(cmb_Process, 1, 0);
            tableLayoutPanel1.Controls.Add(ckb_Selected, 0, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 1;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(807, 30);
            tableLayoutPanel1.TabIndex = 0;
            //
            // btn_DelMsg
            //
            btn_DelMsg.Dock = DockStyle.Fill;
            btn_DelMsg.Location = new Point(223, 3);
            btn_DelMsg.Name = "btn_DelMsg";
            btn_DelMsg.Size = new Size(44, 24);
            btn_DelMsg.TabIndex = 29;
            btn_DelMsg.Text = "-";
            btn_DelMsg.UseVisualStyleBackColor = true;
            btn_DelMsg.Click += btnDelMsg_Click;
            //
            // btn_AddMsg
            //
            btn_AddMsg.Dock = DockStyle.Fill;
            btn_AddMsg.Location = new Point(173, 3);
            btn_AddMsg.Name = "btn_AddMsg";
            btn_AddMsg.Size = new Size(44, 24);
            btn_AddMsg.TabIndex = 28;
            btn_AddMsg.Text = "+";
            btn_AddMsg.UseVisualStyleBackColor = true;
            btn_AddMsg.Click += btnAddMsg_Click;
            //
            // cmb_Process
            //
            cmb_Process.Dock = DockStyle.Fill;
            cmb_Process.FormattingEnabled = true;
            cmb_Process.Location = new Point(23, 3);
            cmb_Process.Name = "cmb_Process";
            cmb_Process.Size = new Size(144, 25);
            cmb_Process.TabIndex = 7;
            //
            // ckb_Selected
            //
            ckb_Selected.AutoSize = true;
            ckb_Selected.Dock = DockStyle.Fill;
            ckb_Selected.Location = new Point(3, 3);
            ckb_Selected.Name = "ckb_Selected";
            ckb_Selected.Size = new Size(14, 24);
            ckb_Selected.TabIndex = 30;
            ckb_Selected.Text = " ";
            ckb_Selected.UseVisualStyleBackColor = true;
            //
            // CsvSettingControl
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(tableLayoutPanel1);
            Name = "CsvSettingControl";
            Size = new Size(807, 30);
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel1.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private ComboBox cmb_Process;
        private Button btn_AddMsg;
        private Button btn_DelMsg;
        private CheckBox ckb_Selected;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,257 @@
using HalconDotNet;
using LB_SmartVision.ProcessRun;
using OpenCvSharp.Flann;
using ReaLTaiizor.Controls;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class CsvSettingControl : UserControl
    {
        ConcurrentDictionary<string, ComboBox> dicComboxs = new ConcurrentDictionary<string, ComboBox>();
        public bool IsSelected { get { return ckb_Selected.Checked; } }
        public string Title { get { return RunBll.Name; } }
        private CsvSetting csv { get; set; } = new CsvSetting();
        private ProcessRunBll RunBll
        {
            get
            {
                if (GlobalVar.dicProcesses.ContainsKey(cmb_Process.Text))
                    return GlobalVar.dicProcesses[cmb_Process.Text];
                else
                    return null;
            }
        }
        public CsvSettingControl(CsvSetting csv = null)
        {
            InitializeComponent();
            if (csv == null)
                csv = new CsvSetting();
            this.csv = csv;
            cmb_Process.MouseClick += MouseClick;
            cmb_Process.SelectedIndexChanged += SelectedIndexChanged;
            cmb_Process.Items.Clear();
            cmb_Process.Items.Add("");
            cmb_Process.Items.AddRange(GlobalVar.dicProcesses.Keys.ToArray());
            cmb_Process.Text = csv.ProcessName;
            if (csv.Others.Count > 0)
            {
                Single perSpace = 100 / csv.Others.Count;
                while (tableLayoutPanel1.ColumnCount - 4 < csv.Others.Count)
                {
                    tableLayoutPanel1.ColumnCount++;
                    tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, perSpace));
                }
                for (int i = 4; i < tableLayoutPanel1.ColumnCount; i++)
                {
                    tableLayoutPanel1.ColumnStyles[i].SizeType = SizeType.Percent;
                    tableLayoutPanel1.ColumnStyles[i].Width = perSpace;
                }
                int index = 0;
                foreach (var value in csv.Others)
                {
                    string key = $"cmb{index}";
                    if (!dicComboxs.ContainsKey(key))
                    {
                        ComboBox comboBox = new ComboBox();
                        comboBox.Name = key;
                        comboBox.MouseClick += MouseClick;
                        comboBox.SelectedIndexChanged += SelectedIndexChanged;
                        comboBox.Text = value;
                        comboBox.Dock = DockStyle.Fill;
                        tableLayoutPanel1.Controls.Add(comboBox, index + 4, 0);
                        dicComboxs.TryAdd(key, comboBox);
                    }
                    else
                        dicComboxs[key].Text = value;
                    index++;
                }
            }
            // æ¢å¤å¸ƒå±€ï¼ˆåªè§¦å‘一次重绘)
            tableLayoutPanel1.ResumeLayout(false);
            this.ResumeLayout(false);
        }
        private void MouseClick(object sender, EventArgs e)
        {
            switch ((sender as ComboBox).Name)
            {
                case "cmbProcess":
                    cmb_Process.Items.Clear();
                    cmb_Process.Items.Add("");
                    cmb_Process.Items.AddRange(GlobalVar.dicProcesses.Keys.ToArray());
                    break;
                default:
                    ComboBox comboBox = sender as ComboBox;
                    if (comboBox != null && comboBox.Name.StartsWith("cmb"))
                    {
                        comboBox.Items.Clear();
                        comboBox.Items.Add("");
                        if (RunBll == null)
                            return;
                        foreach (var lstOutput in RunBll.dicOutputsMapping)
                        {
                            foreach (var output in lstOutput.Value)
                                comboBox.Items.Add(output);
                        }
                        foreach (var lstInput in RunBll.dicInputsMapping)
                        {
                            foreach (var tuple in lstInput.Value)
                            {
                                string inputs = tuple.Item1;
                                comboBox.Items.Add(inputs);
                            }
                        }
                    }
                    break;
            }
        }
        private void SelectedIndexChanged(object sender, EventArgs e)
        {
            switch ((sender as ComboBox).Name)
            {
                case "cmbProcess":
                    csv.ProcessName = cmb_Process.Text;
                    break;
                default:
                    // æ›´æ–°å­—å…¸
                    ComboBox comboBox = sender as ComboBox;
                    if (comboBox != null && comboBox.Name.StartsWith("cmb"))
                    {
                        if (int.TryParse(comboBox.Name.Replace("cmb", ""), out int index))
                        {
                            if (index < csv.Others.Count)
                                csv.Others[index] = comboBox.Text;
                            else
                                csv.Others.Add(comboBox.Text);
                        }
                    }
                    break;
            }
        }
        private void btnAddMsg_Click(object sender, EventArgs e)
        {
            csv.Others.Add("");
            this.BeginInvoke(new Action(() =>
            {
                if (csv.Others.Count > 0)
                {
                    Single perSpace = 100 / csv.Others.Count;
                    while (tableLayoutPanel1.ColumnCount - 4 < csv.Others.Count)
                    {
                        tableLayoutPanel1.ColumnCount++;
                        tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, perSpace));
                    }
                    for (int i = 4; i < tableLayoutPanel1.ColumnCount; i++)
                    {
                        tableLayoutPanel1.ColumnStyles[i].SizeType = SizeType.Percent;
                        tableLayoutPanel1.ColumnStyles[i].Width = perSpace;
                    }
                    int index = 0;
                    foreach (var value in csv.Others)
                    {
                        string key = $"cmb{index}";
                        if (!dicComboxs.ContainsKey(key))
                        {
                            ComboBox comboBox = new ComboBox();
                            comboBox.Name = key;
                            comboBox.MouseClick += MouseClick;
                            comboBox.SelectedIndexChanged += SelectedIndexChanged;
                            comboBox.Text = value;
                            comboBox.Dock = DockStyle.Fill;
                            tableLayoutPanel1.Controls.Add(comboBox, index + 4, 0);
                            dicComboxs.TryAdd(key, comboBox);
                        }
                        else
                            dicComboxs[key].Text = value;
                        index++;
                    }
                }
            }));
        }
        private void btnDelMsg_Click(object sender, EventArgs e)
        {
            if (csv.Others.Count <= 0)
                return;
            if (dicComboxs.TryRemove($"cmb{csv.Others.Count - 1}", out ComboBox cmb))
            {
                cmb.MouseClick -= MouseClick;
                cmb.SelectedIndexChanged -= SelectedIndexChanged;
                tableLayoutPanel1.Controls.Remove(cmb);
                csv.Others.RemoveAt(csv.Others.Count - 1);
            }
            this.BeginInvoke(new Action(() =>
            {
                if (csv.Others.Count > 0)
                {
                    Single perSpace = 100 / csv.Others.Count;
                    tableLayoutPanel1.ColumnCount--;
                    tableLayoutPanel1.ColumnStyles.RemoveAt(tableLayoutPanel1.ColumnStyles.Count - 1);
                    for (int i = 4; i < tableLayoutPanel1.ColumnCount; i++)
                    {
                        tableLayoutPanel1.ColumnStyles[i].SizeType = SizeType.Percent;
                        tableLayoutPanel1.ColumnStyles[i].Width = perSpace;
                    }
                    int index = 0;
                    foreach (var value in csv.Others)
                    {
                        string key = $"cmb{index}";
                        if (!dicComboxs.ContainsKey(key))
                        {
                            ComboBox comboBox = new ComboBox();
                            comboBox.Name = key;
                            comboBox.MouseClick += MouseClick;
                            comboBox.SelectedIndexChanged += SelectedIndexChanged;
                            comboBox.Text = value;
                            comboBox.Dock = DockStyle.Fill;
                            tableLayoutPanel1.Controls.Add(comboBox, index + 4, 0);
                            dicComboxs.TryAdd(key, comboBox);
                        }
                        else
                            dicComboxs[key].Text = value;
                        index++;
                    }
                }
            }));
        }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/CsvSettingControl.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,341 @@
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class LayoutPage
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel3 = new TableLayoutPanel();
            btn_Add = new ReaLTaiizor.Controls.ForeverButton();
            btn_Del = new ReaLTaiizor.Controls.AirButton();
            btn_Save = new ReaLTaiizor.Controls.HopeButton();
            btn_Top = new ReaLTaiizor.Controls.AirButton();
            tableLayoutPanel2 = new TableLayoutPanel();
            pnlLayout = new Panel();
            tableLayoutPanel4 = new TableLayoutPanel();
            label7 = new Label();
            label6 = new Label();
            label5 = new Label();
            label4 = new Label();
            label3 = new Label();
            label1 = new Label();
            label2 = new Label();
            label8 = new Label();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel3.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            tableLayoutPanel4.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(tableLayoutPanel3, 0, 1);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(772, 535);
            tableLayoutPanel1.TabIndex = 0;
            //
            // tableLayoutPanel3
            //
            tableLayoutPanel3.ColumnCount = 6;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.Controls.Add(btn_Add, 5, 0);
            tableLayoutPanel3.Controls.Add(btn_Del, 0, 0);
            tableLayoutPanel3.Controls.Add(btn_Save, 4, 0);
            tableLayoutPanel3.Controls.Add(btn_Top, 1, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 488);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 1;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Size = new Size(766, 44);
            tableLayoutPanel3.TabIndex = 2;
            //
            // btn_Add
            //
            btn_Add.BackColor = Color.Transparent;
            btn_Add.BaseColor = Color.FromArgb(35, 168, 109);
            btn_Add.Dock = DockStyle.Fill;
            btn_Add.Font = new Font("宋体", 12F);
            btn_Add.Location = new Point(638, 3);
            btn_Add.MinimumSize = new Size(1, 1);
            btn_Add.Name = "btn_Add";
            btn_Add.Rounded = false;
            btn_Add.Size = new Size(125, 38);
            btn_Add.TabIndex = 3;
            btn_Add.Text = "添加";
            btn_Add.TextColor = Color.FromArgb(243, 243, 243);
            btn_Add.Click += btnAdd_Click;
            //
            // btn_Del
            //
            btn_Del.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            btn_Del.Font = new Font("Segoe UI", 9F);
            btn_Del.Image = null;
            btn_Del.Location = new Point(3, 3);
            btn_Del.Name = "btn_Del";
            btn_Del.NoRounding = false;
            btn_Del.Size = new Size(121, 38);
            btn_Del.TabIndex = 4;
            btn_Del.Text = "移除";
            btn_Del.Transparent = false;
            btn_Del.Click += btnDel_Click;
            //
            // btn_Save
            //
            btn_Save.BorderColor = Color.FromArgb(220, 223, 230);
            btn_Save.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btn_Save.DangerColor = Color.FromArgb(245, 108, 108);
            btn_Save.DefaultColor = Color.FromArgb(255, 255, 255);
            btn_Save.Font = new Font("Segoe UI", 12F);
            btn_Save.HoverTextColor = Color.FromArgb(48, 49, 51);
            btn_Save.InfoColor = Color.FromArgb(144, 147, 153);
            btn_Save.Location = new Point(511, 3);
            btn_Save.Name = "btn_Save";
            btn_Save.PrimaryColor = Color.FromArgb(64, 158, 255);
            btn_Save.Size = new Size(121, 38);
            btn_Save.SuccessColor = Color.FromArgb(103, 194, 58);
            btn_Save.TabIndex = 5;
            btn_Save.Text = "保存";
            btn_Save.TextColor = Color.White;
            btn_Save.WarningColor = Color.FromArgb(230, 162, 60);
            //
            // btn_Top
            //
            btn_Top.Customization = "7e3t//Ly8v/r6+v/5ubm/+vr6//f39//p6en/zw8PP8UFBT/gICA/w==";
            btn_Top.Dock = DockStyle.Fill;
            btn_Top.Font = new Font("Segoe UI", 9F);
            btn_Top.Image = null;
            btn_Top.Location = new Point(130, 3);
            btn_Top.Name = "btn_Top";
            btn_Top.NoRounding = false;
            btn_Top.Size = new Size(121, 38);
            btn_Top.TabIndex = 6;
            btn_Top.Text = "上移";
            btn_Top.Transparent = false;
            btn_Top.Click += btnTop_Click;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 1;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Controls.Add(pnlLayout, 0, 1);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel4, 0, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.ForeColor = SystemColors.Control;
            tableLayoutPanel2.Location = new Point(2, 2);
            tableLayoutPanel2.Margin = new Padding(2);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 2;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 24F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(768, 481);
            tableLayoutPanel2.TabIndex = 6;
            //
            // pnlLayout
            //
            pnlLayout.Dock = DockStyle.Fill;
            pnlLayout.Location = new Point(3, 27);
            pnlLayout.Name = "pnlLayout";
            pnlLayout.Size = new Size(762, 451);
            pnlLayout.TabIndex = 3;
            //
            // tableLayoutPanel4
            //
            tableLayoutPanel4.ColumnCount = 8;
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 147F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel4.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2881641F));
            tableLayoutPanel4.Controls.Add(label7, 6, 0);
            tableLayoutPanel4.Controls.Add(label6, 5, 0);
            tableLayoutPanel4.Controls.Add(label5, 4, 0);
            tableLayoutPanel4.Controls.Add(label4, 3, 0);
            tableLayoutPanel4.Controls.Add(label3, 2, 0);
            tableLayoutPanel4.Controls.Add(label1, 0, 0);
            tableLayoutPanel4.Controls.Add(label2, 1, 0);
            tableLayoutPanel4.Controls.Add(label8, 7, 0);
            tableLayoutPanel4.Dock = DockStyle.Fill;
            tableLayoutPanel4.Location = new Point(2, 2);
            tableLayoutPanel4.Margin = new Padding(2);
            tableLayoutPanel4.Name = "tableLayoutPanel4";
            tableLayoutPanel4.RowCount = 1;
            tableLayoutPanel4.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel4.Size = new Size(764, 20);
            tableLayoutPanel4.TabIndex = 4;
            //
            // label7
            //
            label7.AutoSize = true;
            label7.Dock = DockStyle.Fill;
            label7.Location = new Point(589, 0);
            label7.Margin = new Padding(2, 0, 2, 0);
            label7.Name = "label7";
            label7.Size = new Size(84, 20);
            label7.TabIndex = 6;
            label7.Text = "存图路径";
            label7.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label6
            //
            label6.AutoSize = true;
            label6.Dock = DockStyle.Fill;
            label6.Location = new Point(501, 0);
            label6.Margin = new Padding(2, 0, 2, 0);
            label6.Name = "label6";
            label6.Size = new Size(84, 20);
            label6.TabIndex = 5;
            label6.Text = "绘制结果3";
            label6.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label5
            //
            label5.AutoSize = true;
            label5.Dock = DockStyle.Fill;
            label5.Location = new Point(413, 0);
            label5.Margin = new Padding(2, 0, 2, 0);
            label5.Name = "label5";
            label5.Size = new Size(84, 20);
            label5.TabIndex = 4;
            label5.Text = "绘制结果2";
            label5.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label4
            //
            label4.AutoSize = true;
            label4.Dock = DockStyle.Fill;
            label4.Location = new Point(325, 0);
            label4.Margin = new Padding(2, 0, 2, 0);
            label4.Name = "label4";
            label4.Size = new Size(84, 20);
            label4.TabIndex = 3;
            label4.Text = "绘制结果1";
            label4.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label3
            //
            label3.AutoSize = true;
            label3.Dock = DockStyle.Fill;
            label3.Location = new Point(237, 0);
            label3.Margin = new Padding(2, 0, 2, 0);
            label3.Name = "label3";
            label3.Size = new Size(84, 20);
            label3.TabIndex = 2;
            label3.Text = "显示图片";
            label3.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label1
            //
            label1.AutoSize = true;
            label1.Dock = DockStyle.Fill;
            label1.ForeColor = SystemColors.Control;
            label1.Location = new Point(2, 0);
            label1.Margin = new Padding(2, 0, 2, 0);
            label1.Name = "label1";
            label1.Size = new Size(143, 20);
            label1.TabIndex = 0;
            label1.Text = "显示名称";
            label1.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label2
            //
            label2.AutoSize = true;
            label2.Dock = DockStyle.Fill;
            label2.Location = new Point(149, 0);
            label2.Margin = new Padding(2, 0, 2, 0);
            label2.Name = "label2";
            label2.Size = new Size(84, 20);
            label2.TabIndex = 1;
            label2.Text = "关联流程";
            label2.TextAlign = ContentAlignment.MiddleCenter;
            //
            // label8
            //
            label8.AutoSize = true;
            label8.Dock = DockStyle.Fill;
            label8.Location = new Point(677, 0);
            label8.Margin = new Padding(2, 0, 2, 0);
            label8.Name = "label8";
            label8.Size = new Size(85, 20);
            label8.TabIndex = 7;
            label8.Text = "图片前缀";
            label8.TextAlign = ContentAlignment.MiddleCenter;
            //
            // LayoutPage
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(tableLayoutPanel1);
            Name = "LayoutPage";
            Size = new Size(772, 535);
            Paint += LayoutPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel3.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            tableLayoutPanel4.ResumeLayout(false);
            tableLayoutPanel4.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel3;
        private ReaLTaiizor.Controls.ForeverButton btn_Add;
        private Panel pnlLayout;
        private ReaLTaiizor.Controls.AirButton btn_Del;
        private ReaLTaiizor.Controls.HopeButton btn_Save;
        private TableLayoutPanel tableLayoutPanel2;
        private TableLayoutPanel tableLayoutPanel4;
        private Label label1;
        private Label label2;
        private Label label6;
        private Label label5;
        private Label label4;
        private Label label3;
        private Label label7;
        private Label label8;
        private ReaLTaiizor.Controls.AirButton btn_Top;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class LayoutPage : UserControl
    {
        public LayoutPage()
        {
            InitializeComponent();
            btn_Save.Click += (sender, e) =>
            {
                if (!VisionForm.SaveAllLayout())
                    MessageBox.Show("!!!保存失败!!!", "异常");
                else
                    MessageBox.Show("保存成功!");
            };
        }
        private void LayoutPage_Paint(object sender, PaintEventArgs e)
        {
            this.pnlLayout.Controls.Clear();
            for (int index = 0; index < GlobalVar.dicLayout.Count; index++)
            {
                LayoutSettingControl control = new LayoutSettingControl(GlobalVar.dicLayout[index]);
                control.Size = new Size(this.pnlLayout.Size.Width, control.Size.Height);
                control.Location = new Point(0, control.Size.Height * index);
                this.pnlLayout.Controls.Add(control);
            }
        }
        private void btnAdd_Click(object sender, EventArgs e)
        {
            Layout layout = new Layout(GlobalVar.strApplicationPath + "\\生产图片");
            foreach (var item in GlobalVar.dicLayout.Values)
            {
                if (item.Title == layout.Title)
                    layout.Title += "(副本)";
            }
            GlobalVar.dicLayout.TryAdd(GlobalVar.dicLayout.Count, layout);
            this.Invalidate();
        }
        private void btnDel_Click(object sender, EventArgs e)
        {
            foreach (var control in pnlLayout.Controls)
            {
                if (control is LayoutSettingControl layoutSettingControl
                    && layoutSettingControl.IsSelected)
                {
                    var item = GlobalVar.dicLayout.FirstOrDefault(x => x.Value.Title == layoutSettingControl.Title);
                    GlobalVar.dicLayout.TryRemove(item.Key, out _);
                }
            }
            this.Invalidate();
        }
        private void btnTop_Click(object sender, EventArgs e)
        {
            bool isSelected = false;
            foreach (var control in pnlLayout.Controls)
            {
                if (control is LayoutSettingControl layoutSettingControl
                    && layoutSettingControl.IsSelected)
                {
                    if (isSelected)
                    {
                        MessageBox.Show("每次只能上移一个!", "异常");
                        return;
                    }
                    isSelected = true;
                }
            }
            for (int index = 0; index < GlobalVar.dicLayout.Count; index++)
            {
                foreach (var control in pnlLayout.Controls)
                {
                    if (control is LayoutSettingControl layoutSettingControl
                        && layoutSettingControl.IsSelected)
                    {
                        var item = GlobalVar.dicLayout.FirstOrDefault(x => x.Value.Title == layoutSettingControl.Title);
                        int Key = item.Key;
                        // å·²ç»æ˜¯ç¬¬ä¸€ä¸ªäº†ï¼Œåˆ™æ— å˜åŒ–
                        if (Key == 0)
                            return;
                        var temp = GlobalVar.dicLayout[Key - 1];
                        GlobalVar.dicLayout[Key - 1] = item.Value;
                        GlobalVar.dicLayout[Key] = temp;
                        this.Invalidate();
                        return;
                    }
                }
            }
        }
    }
    [Serializable]
    public class Layout
    {
        public string Title { get; set; } = "布局";
        public string ProcessName { get; set; } = string.Empty;
        public string InputImage { get; set; } = string.Empty;
        public string SaveImageDir { get; set; } = string.Empty;
        public string SaveImageHead { get; set; } = string.Empty;
        public string ImageTitle { get; set; } = string.Empty;
        public string RecordImage1 { get; set; } = string.Empty;
        public string RecordImage2 { get; set; } = string.Empty;
        public string RecordImage3 { get; set; } = string.Empty;
        public Layout() { }
        public Layout(string path) { SaveImageDir = path; }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/LayoutPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,172 @@
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class LayoutSettingControl
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel1 = new TableLayoutPanel();
            lblName = new CheckBox();
            cmbInputImage = new ComboBox();
            cmbProcess = new ComboBox();
            cmbRecord1 = new ComboBox();
            cmbRecord2 = new ComboBox();
            cmbRecord3 = new ComboBox();
            txtSavePath = new TextBox();
            txtSaveNameHead = new TextBox();
            tableLayoutPanel1.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            tableLayoutPanel1.ColumnCount = 8;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 150F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2853069F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 14.2881641F));
            tableLayoutPanel1.Controls.Add(lblName, 0, 0);
            tableLayoutPanel1.Controls.Add(cmbInputImage, 2, 0);
            tableLayoutPanel1.Controls.Add(cmbProcess, 1, 0);
            tableLayoutPanel1.Controls.Add(cmbRecord1, 3, 0);
            tableLayoutPanel1.Controls.Add(cmbRecord2, 4, 0);
            tableLayoutPanel1.Controls.Add(cmbRecord3, 5, 0);
            tableLayoutPanel1.Controls.Add(txtSavePath, 6, 0);
            tableLayoutPanel1.Controls.Add(txtSaveNameHead, 7, 0);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 1;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Size = new Size(807, 30);
            tableLayoutPanel1.TabIndex = 0;
            //
            // lblName
            //
            lblName.AutoSize = true;
            lblName.Dock = DockStyle.Fill;
            lblName.ForeColor = SystemColors.Control;
            lblName.Location = new Point(3, 3);
            lblName.Name = "lblName";
            lblName.Size = new Size(144, 24);
            lblName.TabIndex = 6;
            lblName.Text = "名称";
            lblName.TextAlign = ContentAlignment.MiddleRight;
            lblName.UseVisualStyleBackColor = true;
            lblName.MouseDown += lblName_MouseDown;
            //
            // cmbInputImage
            //
            cmbInputImage.Dock = DockStyle.Fill;
            cmbInputImage.FormattingEnabled = true;
            cmbInputImage.Location = new Point(246, 3);
            cmbInputImage.Name = "cmbInputImage";
            cmbInputImage.Size = new Size(87, 25);
            cmbInputImage.TabIndex = 0;
            //
            // cmbProcess
            //
            cmbProcess.Dock = DockStyle.Fill;
            cmbProcess.FormattingEnabled = true;
            cmbProcess.Location = new Point(153, 3);
            cmbProcess.Name = "cmbProcess";
            cmbProcess.Size = new Size(87, 25);
            cmbProcess.TabIndex = 7;
            //
            // cmbRecord1
            //
            cmbRecord1.Dock = DockStyle.Fill;
            cmbRecord1.FormattingEnabled = true;
            cmbRecord1.Location = new Point(339, 3);
            cmbRecord1.Name = "cmbRecord1";
            cmbRecord1.Size = new Size(87, 25);
            cmbRecord1.TabIndex = 1;
            //
            // cmbRecord2
            //
            cmbRecord2.Dock = DockStyle.Fill;
            cmbRecord2.FormattingEnabled = true;
            cmbRecord2.Location = new Point(432, 3);
            cmbRecord2.Name = "cmbRecord2";
            cmbRecord2.Size = new Size(87, 25);
            cmbRecord2.TabIndex = 2;
            //
            // cmbRecord3
            //
            cmbRecord3.Dock = DockStyle.Fill;
            cmbRecord3.FormattingEnabled = true;
            cmbRecord3.Location = new Point(525, 3);
            cmbRecord3.Name = "cmbRecord3";
            cmbRecord3.Size = new Size(87, 25);
            cmbRecord3.TabIndex = 5;
            //
            // txtSavePath
            //
            txtSavePath.Dock = DockStyle.Fill;
            txtSavePath.Location = new Point(618, 3);
            txtSavePath.Name = "txtSavePath";
            txtSavePath.Size = new Size(87, 23);
            txtSavePath.TabIndex = 4;
            txtSavePath.MouseDoubleClick += txtSavePath_MouseDoubleClick;
            //
            // txtSaveNameHead
            //
            txtSaveNameHead.Dock = DockStyle.Fill;
            txtSaveNameHead.Location = new Point(711, 3);
            txtSaveNameHead.Name = "txtSaveNameHead";
            txtSaveNameHead.Size = new Size(93, 23);
            txtSaveNameHead.TabIndex = 8;
            txtSaveNameHead.MouseDoubleClick += txtSaveNameHead_MouseDoubleClick;
            //
            // LayoutSettingControl
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(tableLayoutPanel1);
            Name = "LayoutSettingControl";
            Size = new Size(807, 30);
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel1.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel1;
        private ComboBox cmbInputImage;
        private ComboBox cmbRecord1;
        private ComboBox cmbRecord2;
        private TextBox txtSavePath;
        private ComboBox cmbRecord3;
        private CheckBox lblName;
        private ComboBox cmbProcess;
        private TextBox txtSaveNameHead;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,275 @@
using HalconDotNet;
using LB_SmartVision.Forms.Pages.ProcessPage;
using LB_SmartVision.ProcessRun;
using ReaLTaiizor.Controls;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VisionControl.Forms;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class LayoutSettingControl : UserControl
    {
        private Layout layout { get; set; } = new Layout();
        private ProcessRunBll processRunBll
        {
            get
            {
                if (GlobalVar.dicProcesses.ContainsKey(cmbProcess.Text))
                    return GlobalVar.dicProcesses[cmbProcess.Text];
                else
                    return null;
            }
        }
        public bool IsSelected { get { return lblName.Checked; } }
        public string Title { get { return lblName.Text; } }
        public string ProcessName { get { return cmbProcess.Text; } }
        public string InputImage { get { return cmbInputImage.Text; } }
        public string SaveImageDir { get { return txtSavePath.Text; } }
        public string RecordImage1 { get { return cmbRecord1.Text; } }
        public string RecordImage2 { get { return cmbRecord2.Text; } }
        public string RecordImage3 { get { return cmbRecord3.Text; } }
        public LayoutSettingControl(Layout layout = null)
        {
            InitializeComponent();
            this.layout = layout;
            txtSavePath.TextChanged += TextChanged;
            txtSavePath.MouseHover += MouseHover;
            txtSaveNameHead.TextChanged += TextChanged;
            txtSaveNameHead.MouseHover += MouseHover;
            cmbProcess.MouseClick += MouseClick;
            cmbInputImage.MouseClick += MouseClick;
            cmbRecord1.MouseClick += MouseClick;
            cmbRecord2.MouseClick += MouseClick;
            cmbRecord3.MouseClick += MouseClick;
            cmbProcess.SelectedIndexChanged += SelectedIndexChanged;
            cmbInputImage.SelectedIndexChanged += SelectedIndexChanged;
            cmbRecord1.SelectedIndexChanged += SelectedIndexChanged;
            cmbRecord2.SelectedIndexChanged += SelectedIndexChanged;
            cmbRecord3.SelectedIndexChanged += SelectedIndexChanged;
            cmbProcess.Items.Clear();
            cmbProcess.Items.Add("");
            cmbProcess.Items.AddRange(GlobalVar.dicProcesses.Keys.ToArray());
            if (layout != null)
            {
                lblName.Text = layout.Title;
                cmbProcess.Text = layout.ProcessName;
                cmbInputImage.Text = layout.InputImage;
                cmbRecord1.Text = layout.RecordImage1;
                cmbRecord2.Text = layout.RecordImage2;
                cmbRecord3.Text = layout.RecordImage3;
                txtSavePath.Text = layout.SaveImageDir;
                txtSaveNameHead.Text = layout.SaveImageHead;
            }
        }
        private void MouseClick(object sender, EventArgs e)
        {
            switch ((sender as ComboBox).Name)
            {
                case "cmbProcess":
                    cmbProcess.Items.Clear();
                    cmbProcess.Items.Add("");
                    cmbProcess.Items.AddRange(GlobalVar.dicProcesses.Keys.ToArray());
                    break;
                case "cmbInputImage":
                    cmbInputImage.Items.Clear();
                    cmbInputImage.Items.Add("");
                    if (processRunBll == null)
                        return;
                    foreach (var lstOutput in processRunBll.dicOutputsMapping)
                    {
                        foreach (var output in lstOutput.Value)
                        {
                            if (output.Contains("Image"))
                                cmbInputImage.Items.Add($"{lstOutput.Key}.Output.Image");
                        }
                    }
                    break;
                case "cmbRecord1":
                    cmbRecord1.Items.Clear();
                    cmbRecord1.Items.Add("");
                    if (processRunBll == null)
                        return;
                    foreach (var lstOutput in processRunBll.dicOutputsMapping)
                    {
                        foreach (var output in lstOutput.Value)
                        {
                            if (output.Contains("Record"))
                                cmbRecord1.Items.Add($"{lstOutput.Key}.Output.Record");
                        }
                    }
                    break;
                case "cmbRecord2":
                    cmbRecord2.Items.Clear();
                    cmbRecord2.Items.Add("");
                    if (processRunBll == null)
                        return;
                    foreach (var lstOutput in processRunBll.dicOutputsMapping)
                    {
                        foreach (var output in lstOutput.Value)
                        {
                            if (output.Contains("Record"))
                                cmbRecord2.Items.Add($"{lstOutput.Key}.Output.Record");
                        }
                    }
                    break;
                case "cmbRecord3":
                    cmbRecord3.Items.Clear();
                    cmbRecord3.Items.Add("");
                    if (processRunBll == null)
                        return;
                    foreach (var lstOutput in processRunBll.dicOutputsMapping)
                    {
                        foreach (var output in lstOutput.Value)
                        {
                            if (output.Contains("Record"))
                                cmbRecord3.Items.Add($"{lstOutput.Key}.Output.Record");
                        }
                    }
                    break;
            }
        }
        private void SelectedIndexChanged(object sender, EventArgs e)
        {
            switch ((sender as ComboBox).Name)
            {
                case "cmbProcess":
                    layout.ProcessName = cmbProcess.Text;
                    break;
                case "cmbInputImage":
                    layout.InputImage = cmbInputImage.Text;
                    break;
                case "cmbRecord1":
                    layout.RecordImage1 = cmbRecord1.Text;
                    break;
                case "cmbRecord2":
                    layout.RecordImage2 = cmbRecord2.Text;
                    break;
                case "cmbRecord3":
                    layout.RecordImage3 = cmbRecord3.Text;
                    break;
            }
        }
        private void TextChanged(object sender, EventArgs e)
        {
            switch ((sender as TextBox).Name)
            {
                case "txtSavePath":
                    layout.SaveImageDir = txtSavePath.Text;
                    break;
                case "txtSaveNameHead":
                    layout.SaveImageHead = txtSaveNameHead.Text;
                    break;
            }
        }
        private void txtSavePath_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            // åˆ›å»ºæ–‡ä»¶å¤¹é€‰æ‹©å¯¹è¯æ¡†
            using (var folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "请选择文件夹";
                folderDialog.ShowNewFolderButton = true; // å…è®¸åˆ›å»ºæ–°æ–‡ä»¶å¤¹
                folderDialog.RootFolder = Environment.SpecialFolder.MyComputer; // èµ·å§‹ç›®å½•
                // æ˜¾ç¤ºå¯¹è¯æ¡†
                DialogResult result = folderDialog.ShowDialog();
                if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(folderDialog.SelectedPath))
                {
                    string selectedFolder = folderDialog.SelectedPath;
                    txtSavePath.Text = selectedFolder; // è®¾ç½®æ–‡æœ¬æ¡†çš„值为选择的文件夹路径
                }
            }
        }
        private void txtSaveNameHead_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            ProcessOutputsSelectForm processOutputsSelectForm
                       = new ProcessOutputsSelectForm(GlobalVar.dicProcesses[ProcessName].dicInputsMapping, GlobalVar.dicProcesses[ProcessName].dicOutputsMapping);
            processOutputsSelectForm.ShowDialog();
            if (!string.IsNullOrEmpty(processOutputsSelectForm.SelectedOutput))
                txtSaveNameHead.Text += $"{{{processOutputsSelectForm.SelectedOutput}}}";
        }
        private void MouseHover(object sender, EventArgs e)
        {
            if (sender is TextBox txt)
            {
                new ToolTip()
                {
                    ToolTipIcon = ToolTipIcon.Info, // è®¾ç½®æç¤ºå›¾æ ‡
                    UseAnimation = true, // å¯ç”¨åŠ¨ç”»æ•ˆæžœ
                    UseFading = true // å¯ç”¨æ·¡å…¥æ·¡å‡ºæ•ˆæžœ
                }.Show(txt.Text
                    , txt
                    , txt.Width / 2, txt.Height // æ˜¾ç¤ºåœ¨æŽ§ä»¶åº•部中间
                    , 1000); // æ˜¾ç¤º1秒
            }
        }
        private void lblName_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button.ToString() == "Right")
            {
                RenameForm renameForm = new RenameForm(lblName.Text);
                renameForm.ShowDialog();
                if (renameForm.bRename)
                {
                    string oriName = renameForm.strOriName;
                    string newName = renameForm.strNewName;
                    foreach (var layout in GlobalVar.dicLayout.Values)
                    {
                        if (layout.Title == newName)
                        {
                            MessageBox.Show($"变量【{newName}】已存在,请更换名称!", "异常");
                            return;
                        }
                    }
                    foreach (var layout in GlobalVar.dicLayout.Values)
                    {
                        if (layout.Title == oriName && lblName.Checked)
                        {
                            layout.Title = newName;
                            lblName.Text = newName;
                            return;
                        }
                    }
                }
            }
        }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/LayoutSettingControl.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,322 @@
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class RunSettingPage
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            tableLayoutPanel = new TableLayoutPanel();
            txtImagePath = new TextBox();
            cmbImageType = new ComboBox();
            lblImagePath = new Label();
            lblImageType = new Label();
            ckbSaveResultImage = new CheckBox();
            ckbSaveRunImage = new CheckBox();
            txtImageQuality = new TextBox();
            lblImageQuality = new Label();
            btnSave = new Button();
            btnLoad = new Button();
            txtTestSearch = new TextBox();
            btnTest = new Button();
            splitContainer = new SplitContainer();
            tableLayoutPanelTest = new TableLayoutPanel();
            lstControls = new ListBox();
            tableLayoutPanel.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit();
            splitContainer.Panel1.SuspendLayout();
            splitContainer.Panel2.SuspendLayout();
            splitContainer.SuspendLayout();
            tableLayoutPanelTest.SuspendLayout();
            SuspendLayout();
            //
            // tableLayoutPanel
            //
            tableLayoutPanel.ColumnCount = 5;
            tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140F));
            tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F));
            tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 140F));
            tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70F));
            tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel.Controls.Add(txtImagePath, 1, 0);
            tableLayoutPanel.Controls.Add(cmbImageType, 1, 1);
            tableLayoutPanel.Controls.Add(lblImagePath, 0, 0);
            tableLayoutPanel.Controls.Add(lblImageType, 0, 1);
            tableLayoutPanel.Controls.Add(ckbSaveResultImage, 0, 4);
            tableLayoutPanel.Controls.Add(ckbSaveRunImage, 0, 3);
            tableLayoutPanel.Controls.Add(txtImageQuality, 1, 2);
            tableLayoutPanel.Controls.Add(lblImageQuality, 0, 2);
            tableLayoutPanel.Dock = DockStyle.Fill;
            tableLayoutPanel.Location = new Point(0, 0);
            tableLayoutPanel.Margin = new Padding(2);
            tableLayoutPanel.Name = "tableLayoutPanel";
            tableLayoutPanel.RowCount = 12;
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanel.Size = new Size(441, 355);
            tableLayoutPanel.TabIndex = 1;
            //
            // txtImagePath
            //
            txtImagePath.Dock = DockStyle.Fill;
            txtImagePath.Location = new Point(142, 2);
            txtImagePath.Margin = new Padding(2);
            txtImagePath.Name = "txtImagePath";
            txtImagePath.ScrollBars = ScrollBars.Horizontal;
            txtImagePath.Size = new Size(66, 23);
            txtImagePath.TabIndex = 0;
            txtImagePath.WordWrap = false;
            txtImagePath.MouseDoubleClick += txtImagePath_MouseDoubleClick;
            txtImagePath.MouseHover += txtImagePath_MouseHover;
            //
            // cmbImageType
            //
            cmbImageType.Dock = DockStyle.Fill;
            cmbImageType.FormattingEnabled = true;
            cmbImageType.Items.AddRange(new object[] { "jpg", "bmp" });
            cmbImageType.Location = new Point(142, 34);
            cmbImageType.Margin = new Padding(2);
            cmbImageType.Name = "cmbImageType";
            cmbImageType.Size = new Size(66, 25);
            cmbImageType.TabIndex = 1;
            cmbImageType.Text = "jpg";
            //
            // lblImagePath
            //
            lblImagePath.AutoSize = true;
            lblImagePath.ForeColor = SystemColors.Control;
            lblImagePath.Location = new Point(2, 0);
            lblImagePath.Margin = new Padding(2, 0, 2, 0);
            lblImagePath.Name = "lblImagePath";
            lblImagePath.Size = new Size(56, 17);
            lblImagePath.TabIndex = 3;
            lblImagePath.Text = "图片路径";
            lblImagePath.TextAlign = ContentAlignment.TopRight;
            //
            // lblImageType
            //
            lblImageType.AutoSize = true;
            lblImageType.ForeColor = SystemColors.Control;
            lblImageType.Location = new Point(2, 32);
            lblImageType.Margin = new Padding(2, 0, 2, 0);
            lblImageType.Name = "lblImageType";
            lblImageType.Size = new Size(56, 17);
            lblImageType.TabIndex = 4;
            lblImageType.Text = "图片格式";
            lblImageType.TextAlign = ContentAlignment.TopRight;
            //
            // ckbSaveResultImage
            //
            ckbSaveResultImage.AutoSize = true;
            ckbSaveResultImage.ForeColor = SystemColors.Control;
            ckbSaveResultImage.Location = new Point(2, 130);
            ckbSaveResultImage.Margin = new Padding(2);
            ckbSaveResultImage.Name = "ckbSaveResultImage";
            ckbSaveResultImage.Size = new Size(99, 21);
            ckbSaveResultImage.TabIndex = 5;
            ckbSaveResultImage.Text = "保存结果图片";
            ckbSaveResultImage.UseVisualStyleBackColor = true;
            //
            // ckbSaveRunImage
            //
            ckbSaveRunImage.AutoSize = true;
            ckbSaveRunImage.ForeColor = SystemColors.Control;
            ckbSaveRunImage.Location = new Point(2, 98);
            ckbSaveRunImage.Margin = new Padding(2);
            ckbSaveRunImage.Name = "ckbSaveRunImage";
            ckbSaveRunImage.Size = new Size(99, 21);
            ckbSaveRunImage.TabIndex = 2;
            ckbSaveRunImage.Text = "保存运行图片";
            ckbSaveRunImage.UseVisualStyleBackColor = true;
            //
            // txtImageQuality
            //
            txtImageQuality.Location = new Point(142, 66);
            txtImageQuality.Margin = new Padding(2);
            txtImageQuality.Name = "txtImageQuality";
            txtImageQuality.Size = new Size(66, 23);
            txtImageQuality.TabIndex = 7;
            txtImageQuality.Text = "50";
            txtImageQuality.TextChanged += txtImageQuality_TextChanged;
            //
            // lblImageQuality
            //
            lblImageQuality.AutoSize = true;
            lblImageQuality.ForeColor = SystemColors.Control;
            lblImageQuality.Location = new Point(2, 64);
            lblImageQuality.Margin = new Padding(2, 0, 2, 0);
            lblImageQuality.Name = "lblImageQuality";
            lblImageQuality.Size = new Size(56, 17);
            lblImageQuality.TabIndex = 8;
            lblImageQuality.Text = "图片质量";
            lblImageQuality.TextAlign = ContentAlignment.TopRight;
            //
            // btnSave
            //
            btnSave.Location = new Point(2, 66);
            btnSave.Margin = new Padding(2);
            btnSave.Name = "btnSave";
            btnSave.Size = new Size(71, 28);
            btnSave.TabIndex = 2;
            btnSave.Text = "保存";
            btnSave.UseVisualStyleBackColor = true;
            btnSave.Click += btnSave_Click;
            //
            // btnLoad
            //
            btnLoad.Location = new Point(2, 98);
            btnLoad.Margin = new Padding(2);
            btnLoad.Name = "btnLoad";
            btnLoad.Size = new Size(71, 28);
            btnLoad.TabIndex = 3;
            btnLoad.Text = "加载";
            btnLoad.UseVisualStyleBackColor = true;
            btnLoad.Click += btnLoad_Click;
            //
            // txtTestSearch
            //
            txtTestSearch.Dock = DockStyle.Fill;
            txtTestSearch.Location = new Point(2, 2);
            txtTestSearch.Margin = new Padding(2);
            txtTestSearch.Name = "txtTestSearch";
            txtTestSearch.Size = new Size(216, 23);
            txtTestSearch.TabIndex = 4;
            //
            // btnTest
            //
            btnTest.Location = new Point(2, 34);
            btnTest.Margin = new Padding(2);
            btnTest.Name = "btnTest";
            btnTest.Size = new Size(71, 28);
            btnTest.TabIndex = 5;
            btnTest.Text = "测试查找";
            btnTest.UseVisualStyleBackColor = true;
            btnTest.Click += btnTest_Click;
            //
            // splitContainer
            //
            splitContainer.BackColor = Color.FromArgb(32, 41, 50);
            splitContainer.Dock = DockStyle.Fill;
            splitContainer.IsSplitterFixed = true;
            splitContainer.Location = new Point(0, 0);
            splitContainer.Margin = new Padding(2);
            splitContainer.Name = "splitContainer";
            //
            // splitContainer.Panel1
            //
            splitContainer.Panel1.Controls.Add(tableLayoutPanelTest);
            //
            // splitContainer.Panel2
            //
            splitContainer.Panel2.Controls.Add(tableLayoutPanel);
            splitContainer.Size = new Size(664, 355);
            splitContainer.SplitterDistance = 220;
            splitContainer.SplitterWidth = 3;
            splitContainer.TabIndex = 4;
            //
            // tableLayoutPanelTest
            //
            tableLayoutPanelTest.ColumnCount = 1;
            tableLayoutPanelTest.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanelTest.Controls.Add(txtTestSearch, 0, 0);
            tableLayoutPanelTest.Controls.Add(btnTest, 0, 1);
            tableLayoutPanelTest.Controls.Add(btnLoad, 0, 3);
            tableLayoutPanelTest.Controls.Add(btnSave, 0, 2);
            tableLayoutPanelTest.Controls.Add(lstControls, 0, 5);
            tableLayoutPanelTest.Dock = DockStyle.Fill;
            tableLayoutPanelTest.Location = new Point(0, 0);
            tableLayoutPanelTest.Margin = new Padding(2);
            tableLayoutPanelTest.Name = "tableLayoutPanelTest";
            tableLayoutPanelTest.RowCount = 6;
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 32F));
            tableLayoutPanelTest.RowStyles.Add(new RowStyle(SizeType.Absolute, 16F));
            tableLayoutPanelTest.Size = new Size(220, 355);
            tableLayoutPanelTest.TabIndex = 0;
            //
            // lstControls
            //
            lstControls.Dock = DockStyle.Fill;
            lstControls.FormattingEnabled = true;
            lstControls.ItemHeight = 17;
            lstControls.Location = new Point(2, 162);
            lstControls.Margin = new Padding(2);
            lstControls.Name = "lstControls";
            lstControls.ScrollAlwaysVisible = true;
            lstControls.Size = new Size(216, 191);
            lstControls.TabIndex = 6;
            //
            // RunSettingPage
            //
            AutoScaleDimensions = new SizeF(7F, 17F);
            AutoScaleMode = AutoScaleMode.Font;
            Controls.Add(splitContainer);
            Margin = new Padding(2);
            Name = "RunSettingPage";
            Size = new Size(664, 355);
            tableLayoutPanel.ResumeLayout(false);
            tableLayoutPanel.PerformLayout();
            splitContainer.Panel1.ResumeLayout(false);
            splitContainer.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit();
            splitContainer.ResumeLayout(false);
            tableLayoutPanelTest.ResumeLayout(false);
            tableLayoutPanelTest.PerformLayout();
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel;
        private Button btnSave;
        private Button btnLoad;
        private TextBox txtImagePath;
        private ComboBox cmbImageType;
        private CheckBox ckbSaveRunImage;
        private Label lblImagePath;
        private Label lblImageType;
        private CheckBox ckbSaveResultImage;
        private TextBox txtTestSearch;
        private Button btnTest;
        private SplitContainer splitContainer;
        private TableLayoutPanel tableLayoutPanelTest;
        private ListBox lstControls;
        private TextBox txtImageQuality;
        private Label lblImageQuality;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,334 @@
using Newtonsoft.Json;
using System.Data;
using System.Diagnostics;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class RunSettingPage : UserControl
    {
        ControlStateManager controlStateManager { get; set; }
        public RunSettingPage()
        {
            InitializeComponent();
            controlStateManager = new ControlStateManager(tableLayoutPanel);
            lstControls.Items.Clear();
            foreach (Control control in GetAllControls(tableLayoutPanel))
            {
                if (control is TextBox || control is CheckBox || control is ComboBox)
                {
                    if (!string.IsNullOrEmpty(control.Name))
                    {
                        lstControls.Items.Add(control.Name);
                    }
                }
            }
        }
        // èŽ·å–æ‰€æœ‰å­æŽ§ä»¶ï¼ˆé€’å½’ï¼‰
        private IEnumerable<Control> GetAllControls(Control control)
        {
            var controls = control.Controls.Cast<Control>();
            return controls.SelectMany(ctrl => GetAllControls(ctrl)).Concat(controls);
        }
        // ä¿å­˜æ‰€æœ‰æŽ§ä»¶çŠ¶æ€ï¼ˆé€’å½’å¤„ç†å®¹å™¨æŽ§ä»¶ï¼‰
        public void SaveControlsState(TableLayoutPanel tablePanel)
        {
            GlobalVar.ControlStates.Clear();
            SaveControlsRecursive(tablePanel);
        }
        private void SaveControlsRecursive(Control parentControl)
        {
            foreach (Control control in parentControl.Controls)
            {
                // é€’归处理容器控件
                if (control.HasChildren && !(control is ComboBox)) // ComboBox有Children但不是容器控件
                {
                    SaveControlsRecursive(control);
                    continue;
                }
                string key = $"{control.Name}_{control.GetType().Name}";
                switch (control)
                {
                    case TextBox textBox:
                        GlobalVar.ControlStates[key] = textBox.Text;
                        break;
                    case CheckBox checkBox:
                        GlobalVar.ControlStates[key] = checkBox.Checked;
                        break;
                    case ComboBox comboBox:
                        var comboData = new
                        {
                            Items = comboBox.Items.Cast<object>().ToList(),
                            SelectedIndex = comboBox.SelectedIndex
                        };
                        GlobalVar.ControlStates[key] = comboData;
                        break;
                }
            }
        }
        // åŠ è½½æŽ§ä»¶çŠ¶æ€ï¼ˆé€’å½’å¤„ç†å®¹å™¨æŽ§ä»¶ï¼‰
        public void LoadControlsState(TableLayoutPanel tablePanel)
        {
            LoadControlsRecursive(tablePanel);
        }
        private void LoadControlsRecursive(Control parentControl)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() => LoadControlsRecursive(parentControl)));
                return;
            }
            foreach (Control control in parentControl.Controls)
            {
                if (control.HasChildren && !(control is ComboBox))
                {
                    LoadControlsRecursive(control);
                    continue;
                }
                string key = $"{control.Name}_{control.GetType().Name}";
                if (!GlobalVar.ControlStates.TryGetValue(key, out object value)) continue;
                switch (control)
                {
                    case TextBox textBox when value is string text:
                        textBox.Text = text;
                        break;
                    case CheckBox checkBox when value is bool isChecked:
                        checkBox.Checked = isChecked;
                        break;
                    case ComboBox comboBox when value != null:
                        try
                        {
                            // åŠ¨æ€è§£æžComboBox数据
                            var json = JsonConvert.SerializeObject(value);
                            var comboData = JsonConvert.DeserializeAnonymousType(json, new
                            {
                                Items = new List<object>(),
                                SelectedIndex = 0
                            });
                            comboBox.BeginUpdate();
                            comboBox.Items.Clear();
                            comboBox.Items.AddRange(comboData.Items.ToArray());
                            if (comboData.SelectedIndex >= 0 && comboData.SelectedIndex < comboBox.Items.Count)
                            {
                                comboBox.SelectedIndex = comboData.SelectedIndex;
                            }
                            comboBox.EndUpdate();
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine($"加载ComboBox数据失败: {ex.Message}");
                        }
                        break;
                }
            }
        }
        // ä¿å­˜åˆ°JSON文件
        public void SaveToJson(string filePath = "")
        {
            try
            {
                SaveControlsState(tableLayoutPanel);
                if (string.IsNullOrEmpty(filePath))
                    filePath = GlobalVar.allRunSettingStringPath;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    TypeNameHandling = TypeNameHandling.Auto // å¤„理多态类型
                };
                string json = JsonConvert.SerializeObject(GlobalVar.ControlStates, settings);
                File.WriteAllText(filePath, json);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存失败: {ex.Message}", "异常");
            }
        }
        // ä»ŽJSON文件加载
        public void LoadFromJson(string filePath = "")
        {
            try
            {
                if (string.IsNullOrEmpty(filePath))
                    filePath = GlobalVar.allRunSettingStringPath;
                if (!File.Exists(filePath))
                {
                    SaveToJson(filePath);
                    Debug.WriteLine($"文件不存在,已创建新文件: {filePath}");
                }
                string json = File.ReadAllText(filePath);
                var settings = new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto // å¤„理多态类型
                };
                GlobalVar.ControlStates = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, settings);
                LoadControlsState(tableLayoutPanel);
                if (txtImagePath.Text.Trim() == "" || string.IsNullOrEmpty(txtImagePath.Text))
                {
                    // å¦‚果没有设置图片路径,则使用默认路径
                    txtImagePath.Text = GlobalVar.strApplicationPath;
                    SaveToJson(filePath);
                    LoadControlsState(tableLayoutPanel);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载失败: {ex.Message}", "异常");
            }
        }
        private void btnTest_Click(object sender, EventArgs e)
        {
            string searchControlName = txtTestSearch.Text;
            if (searchControlName.StartsWith("txt"))
            {
                // å‡è®¾æ˜¯ TextBox
                TextBox textBox = controlStateManager.GetControl<TextBox>(searchControlName);
                if (textBox != null)
                {
                    MessageBox.Show($"找到控件: {textBox.Name}, æ–‡æœ¬å†…容: {textBox.Text}");
                }
                else
                {
                    MessageBox.Show($"未找到控件: {searchControlName}", "异常");
                }
            }
            else if (searchControlName.StartsWith("ckb"))
            {
                // å‡è®¾æ˜¯ CheckBox
                CheckBox checkBox = controlStateManager.GetControl<CheckBox>(searchControlName);
                if (checkBox != null)
                {
                    MessageBox.Show($"找到控件: {checkBox.Name}, çŠ¶æ€: {checkBox.Checked}");
                }
                else
                {
                    MessageBox.Show($"未找到控件: {searchControlName}", "异常");
                }
            }
            else if (searchControlName.StartsWith("cmb"))
            {
                // å‡è®¾æ˜¯ ComboBox
                ComboBox comboBox = controlStateManager.GetControl<ComboBox>(searchControlName);
                if (comboBox != null)
                {
                    string selectedText = controlStateManager.GetComboBoxText(searchControlName);
                    MessageBox.Show($"找到控件: {comboBox.Name}, é€‰ä¸­é¡¹: {selectedText}");
                }
                else
                {
                    MessageBox.Show($"未找到控件: {searchControlName}", "异常");
                }
            }
            else
            {
                MessageBox.Show("请输入有效的控件名称前缀(txt、ckb、cmb)", "异常");
            }
        }
        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveToJson();
            MessageBox.Show("控件状态已保存");
        }
        private void btnLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            // è®¾ç½®æ–‡ä»¶å¯¹è¯æ¡†çš„属性
            openFileDialog.Multiselect = false; // ä¸å…è®¸å¤šé€‰
            // è®¾ç½®æ–‡ä»¶è¿‡æ»¤å™¨ï¼Œæ”¯æŒå¤šç§æ–‡ä»¶ç±»åž‹
            openFileDialog.Filter = "Ini Files (*.json)|*.json|All Files (*.*)|*.*";
            // æ˜¾ç¤ºæ–‡ä»¶å¯¹è¯æ¡†
            DialogResult result = openFileDialog.ShowDialog();
            // å¤„理对话框返回结果
            if (result == DialogResult.OK)
            {
                // èŽ·å–ç”¨æˆ·é€‰æ‹©çš„æ–‡ä»¶å
                string[] selectedFiles = openFileDialog.FileNames;
                if (selectedFiles.Length > 0)
                {
                    if (File.Exists(selectedFiles[0]))
                    {
                        LoadFromJson(selectedFiles[0]);
                        MessageBox.Show("控件状态已加载");
                    }
                }
            }
        }
        private void txtImagePath_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            // åˆ›å»ºæ–‡ä»¶å¤¹é€‰æ‹©å¯¹è¯æ¡†
            using (var folderDialog = new FolderBrowserDialog())
            {
                folderDialog.Description = "请选择文件夹";
                folderDialog.ShowNewFolderButton = true; // å…è®¸åˆ›å»ºæ–°æ–‡ä»¶å¤¹
                folderDialog.RootFolder = Environment.SpecialFolder.MyComputer; // èµ·å§‹ç›®å½•
                // æ˜¾ç¤ºå¯¹è¯æ¡†
                DialogResult result = folderDialog.ShowDialog();
                if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(folderDialog.SelectedPath))
                {
                    string selectedFolder = folderDialog.SelectedPath;
                    txtImagePath.Text = selectedFolder; // è®¾ç½®æ–‡æœ¬æ¡†çš„值为选择的文件夹路径
                }
            }
        }
        ToolTip pathToolTip = new ToolTip()
        {
            ToolTipIcon = ToolTipIcon.Info, // è®¾ç½®æç¤ºå›¾æ ‡
            UseAnimation = true, // å¯ç”¨åŠ¨ç”»æ•ˆæžœ
            UseFading = true // å¯ç”¨æ·¡å…¥æ·¡å‡ºæ•ˆæžœ
        };
        private void txtImagePath_MouseHover(object sender, EventArgs e)
        {
            pathToolTip.Show(txtImagePath.Text
                , txtImagePath
                , txtImagePath.Width / 2, txtImagePath.Height // æ˜¾ç¤ºåœ¨æŽ§ä»¶åº•部中间
                , 1000); // æ˜¾ç¤º1秒
        }
        private void txtImageQuality_TextChanged(object sender, EventArgs e)
        {
            if (int.TryParse(txtImageQuality.Text, out int quality))
            {
                if (quality < 0 || quality > 100)
                {
                    MessageBox.Show("图像质量必须在0到100之间!", "异常");
                    txtImageQuality.Text = "100"; // é‡ç½®ä¸ºé»˜è®¤å€¼
                }
            }
            else
            {
                MessageBox.Show("请输入有效的数字!", "异常");
                txtImageQuality.Text = "100"; // é‡ç½®ä¸ºé»˜è®¤å€¼
            }
        }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/RunSettingPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,372 @@
using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    partial class SettingEditPage
    {
        /// <summary>
        /// å¿…需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// æ¸…理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region ç»„件设计器生成的代码
        /// <summary>
        /// è®¾è®¡å™¨æ”¯æŒæ‰€éœ€çš„æ–¹æ³• - ä¸è¦ä¿®æ”¹
        /// ä½¿ç”¨ä»£ç ç¼–辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            dataGridView = new DataGridView();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel3 = new TableLayoutPanel();
            btnSaveProcessSetting = new ForeverButton();
            btnAdd = new HopeButton();
            grpSetting = new ParrotGroupBox();
            grpProcess = new ParrotGroupBox();
            tableLayoutPanel1 = new TableLayoutPanel();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel5 = new TableLayoutPanel();
            btn_AddProcess = new HopeButton();
            splitContainer1 = new SplitContainer();
            poisonTabControl1 = new PoisonTabControl();
            pageProcesses = new System.Windows.Forms.TabPage();
            pageSetting = new System.Windows.Forms.TabPage();
            pageLayout = new System.Windows.Forms.TabPage();
            pageCsv = new System.Windows.Forms.TabPage();
            ((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit();
            tableLayoutPanel2.SuspendLayout();
            tableLayoutPanel3.SuspendLayout();
            grpSetting.SuspendLayout();
            grpProcess.SuspendLayout();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel5.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
            splitContainer1.Panel1.SuspendLayout();
            splitContainer1.Panel2.SuspendLayout();
            splitContainer1.SuspendLayout();
            poisonTabControl1.SuspendLayout();
            pageProcesses.SuspendLayout();
            SuspendLayout();
            //
            // dataGridView
            //
            dataGridView.BackgroundColor = Color.FromArgb(32, 41, 50);
            dataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
            dataGridView.Dock = DockStyle.Fill;
            dataGridView.GridColor = SystemColors.Info;
            dataGridView.Location = new Point(3, 3);
            dataGridView.Name = "dataGridView";
            dataGridView.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
            dataGridView.Size = new Size(840, 184);
            dataGridView.TabIndex = 0;
            dataGridView.CellBeginEdit += dataGridView_CellBeginEdit;
            dataGridView.CellContentClick += dataGridView_CellContentClick;
            dataGridView.CellEndEdit += dataGridView_CellEndEdit;
            dataGridView.UserDeletingRow += dataGridView_UserDeletingRow;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 1;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Controls.Add(dataGridView, 0, 0);
            tableLayoutPanel2.Controls.Add(tableLayoutPanel3, 0, 1);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 19);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 2;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel2.Size = new Size(846, 240);
            tableLayoutPanel2.TabIndex = 2;
            //
            // tableLayoutPanel3
            //
            tableLayoutPanel3.ColumnCount = 6;
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel3.Controls.Add(btnSaveProcessSetting, 5, 0);
            tableLayoutPanel3.Controls.Add(btnAdd, 4, 0);
            tableLayoutPanel3.Dock = DockStyle.Fill;
            tableLayoutPanel3.Location = new Point(3, 193);
            tableLayoutPanel3.Name = "tableLayoutPanel3";
            tableLayoutPanel3.RowCount = 1;
            tableLayoutPanel3.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel3.Size = new Size(840, 44);
            tableLayoutPanel3.TabIndex = 1;
            //
            // btnSaveProcessSetting
            //
            btnSaveProcessSetting.BackColor = Color.Transparent;
            btnSaveProcessSetting.BaseColor = Color.FromArgb(35, 168, 109);
            btnSaveProcessSetting.Dock = DockStyle.Fill;
            btnSaveProcessSetting.Font = new Font("宋体", 12F);
            btnSaveProcessSetting.Location = new Point(703, 3);
            btnSaveProcessSetting.MinimumSize = new Size(1, 1);
            btnSaveProcessSetting.Name = "btnSaveProcessSetting";
            btnSaveProcessSetting.Rounded = false;
            btnSaveProcessSetting.Size = new Size(134, 38);
            btnSaveProcessSetting.TabIndex = 3;
            btnSaveProcessSetting.Text = "保存";
            btnSaveProcessSetting.TextColor = Color.FromArgb(243, 243, 243);
            btnSaveProcessSetting.Click += btn_SaveProcessSetting_Click;
            //
            // btnAdd
            //
            btnAdd.BorderColor = Color.FromArgb(220, 223, 230);
            btnAdd.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btnAdd.DangerColor = Color.FromArgb(245, 108, 108);
            btnAdd.DefaultColor = Color.FromArgb(255, 255, 255);
            btnAdd.Dock = DockStyle.Fill;
            btnAdd.Font = new Font("宋体", 12F);
            btnAdd.HoverTextColor = Color.FromArgb(48, 49, 51);
            btnAdd.InfoColor = Color.FromArgb(144, 147, 153);
            btnAdd.Location = new Point(563, 3);
            btnAdd.MinimumSize = new Size(1, 1);
            btnAdd.Name = "btnAdd";
            btnAdd.PrimaryColor = Color.FromArgb(64, 158, 255);
            btnAdd.Size = new Size(134, 38);
            btnAdd.SuccessColor = Color.FromArgb(103, 194, 58);
            btnAdd.TabIndex = 4;
            btnAdd.Text = "添加";
            btnAdd.TextColor = Color.White;
            btnAdd.WarningColor = Color.FromArgb(230, 162, 60);
            btnAdd.Click += btn_Add_Click;
            //
            // grpSetting
            //
            grpSetting.BorderColor = Color.DodgerBlue;
            grpSetting.BorderWidth = 1;
            grpSetting.Controls.Add(tableLayoutPanel2);
            grpSetting.Dock = DockStyle.Fill;
            grpSetting.Location = new Point(0, 0);
            grpSetting.Name = "grpSetting";
            grpSetting.ShowText = true;
            grpSetting.Size = new Size(852, 262);
            grpSetting.TabIndex = 5;
            grpSetting.TabStop = false;
            grpSetting.Text = "通讯触发流程设置";
            grpSetting.TextColor = Color.DodgerBlue;
            //
            // grpProcess
            //
            grpProcess.BorderColor = Color.DodgerBlue;
            grpProcess.BorderWidth = 1;
            grpProcess.Controls.Add(tableLayoutPanel1);
            grpProcess.Dock = DockStyle.Fill;
            grpProcess.Location = new Point(0, 0);
            grpProcess.Name = "grpProcess";
            grpProcess.ShowText = true;
            grpProcess.Size = new Size(852, 266);
            grpProcess.TabIndex = 5;
            grpProcess.TabStop = false;
            grpProcess.Text = "流程设置";
            grpProcess.TextColor = Color.DodgerBlue;
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel5, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(3, 19);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(846, 244);
            tableLayoutPanel1.TabIndex = 3;
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.AutoScroll = true;
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(838, 184);
            uiFlowLayoutPanel1.TabIndex = 11;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel5
            //
            tableLayoutPanel5.ColumnCount = 6;
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel5.Controls.Add(btn_AddProcess, 0, 0);
            tableLayoutPanel5.Dock = DockStyle.Fill;
            tableLayoutPanel5.Location = new Point(3, 197);
            tableLayoutPanel5.Name = "tableLayoutPanel5";
            tableLayoutPanel5.RowCount = 1;
            tableLayoutPanel5.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel5.Size = new Size(840, 44);
            tableLayoutPanel5.TabIndex = 1;
            //
            // btn_AddProcess
            //
            btn_AddProcess.BorderColor = Color.FromArgb(220, 223, 230);
            btn_AddProcess.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btn_AddProcess.DangerColor = Color.FromArgb(245, 108, 108);
            btn_AddProcess.DefaultColor = Color.FromArgb(255, 255, 255);
            btn_AddProcess.Dock = DockStyle.Fill;
            btn_AddProcess.Font = new Font("宋体", 12F);
            btn_AddProcess.HoverTextColor = Color.FromArgb(48, 49, 51);
            btn_AddProcess.InfoColor = Color.FromArgb(144, 147, 153);
            btn_AddProcess.Location = new Point(3, 3);
            btn_AddProcess.MinimumSize = new Size(1, 1);
            btn_AddProcess.Name = "btn_AddProcess";
            btn_AddProcess.PrimaryColor = Color.FromArgb(64, 158, 255);
            btn_AddProcess.Size = new Size(134, 38);
            btn_AddProcess.SuccessColor = Color.FromArgb(103, 194, 58);
            btn_AddProcess.TabIndex = 4;
            btn_AddProcess.Text = "新建流程";
            btn_AddProcess.TextColor = Color.White;
            btn_AddProcess.WarningColor = Color.FromArgb(230, 162, 60);
            btn_AddProcess.Click += btn_AddProcess_Click;
            //
            // splitContainer1
            //
            splitContainer1.BackColor = Color.FromArgb(32, 41, 50);
            splitContainer1.Dock = DockStyle.Fill;
            splitContainer1.Location = new Point(3, 3);
            splitContainer1.Name = "splitContainer1";
            splitContainer1.Orientation = Orientation.Horizontal;
            //
            // splitContainer1.Panel1
            //
            splitContainer1.Panel1.Controls.Add(grpProcess);
            //
            // splitContainer1.Panel2
            //
            splitContainer1.Panel2.Controls.Add(grpSetting);
            splitContainer1.Size = new Size(852, 532);
            splitContainer1.SplitterDistance = 266;
            splitContainer1.TabIndex = 6;
            //
            // poisonTabControl1
            //
            poisonTabControl1.Controls.Add(pageProcesses);
            poisonTabControl1.Controls.Add(pageSetting);
            poisonTabControl1.Controls.Add(pageLayout);
            poisonTabControl1.Controls.Add(pageCsv);
            poisonTabControl1.Dock = DockStyle.Fill;
            poisonTabControl1.Location = new Point(0, 0);
            poisonTabControl1.Name = "poisonTabControl1";
            poisonTabControl1.Padding = new Point(6, 8);
            poisonTabControl1.SelectedIndex = 0;
            poisonTabControl1.Size = new Size(866, 580);
            poisonTabControl1.TabIndex = 7;
            poisonTabControl1.UseSelectable = true;
            //
            // pageProcesses
            //
            pageProcesses.Controls.Add(splitContainer1);
            pageProcesses.Location = new Point(4, 38);
            pageProcesses.Name = "pageProcesses";
            pageProcesses.Padding = new Padding(3);
            pageProcesses.Size = new Size(858, 538);
            pageProcesses.TabIndex = 0;
            pageProcesses.Text = "流程设置";
            pageProcesses.UseVisualStyleBackColor = true;
            //
            // pageSetting
            //
            pageSetting.BackColor = Color.FromArgb(32, 41, 50);
            pageSetting.Location = new Point(4, 38);
            pageSetting.Name = "pageSetting";
            pageSetting.Padding = new Padding(3);
            pageSetting.Size = new Size(858, 538);
            pageSetting.TabIndex = 1;
            pageSetting.Text = "运行设置";
            //
            // pageLayout
            //
            pageLayout.BackColor = Color.FromArgb(32, 41, 50);
            pageLayout.Location = new Point(4, 38);
            pageLayout.Name = "pageLayout";
            pageLayout.Size = new Size(858, 538);
            pageLayout.TabIndex = 2;
            pageLayout.Text = "流程布局";
            //
            // pageCsv
            //
            pageCsv.BackColor = Color.FromArgb(32, 41, 50);
            pageCsv.Location = new Point(4, 38);
            pageCsv.Name = "pageCsv";
            pageCsv.Padding = new Padding(3);
            pageCsv.Size = new Size(858, 538);
            pageCsv.TabIndex = 3;
            pageCsv.Text = "流程表格";
            //
            // SettingEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(poisonTabControl1);
            Name = "SettingEditPage";
            Size = new Size(866, 580);
            Paint += SettingEditPage_Paint;
            ((System.ComponentModel.ISupportInitialize)dataGridView).EndInit();
            tableLayoutPanel2.ResumeLayout(false);
            tableLayoutPanel3.ResumeLayout(false);
            grpSetting.ResumeLayout(false);
            grpSetting.PerformLayout();
            grpProcess.ResumeLayout(false);
            grpProcess.PerformLayout();
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel5.ResumeLayout(false);
            splitContainer1.Panel1.ResumeLayout(false);
            splitContainer1.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
            splitContainer1.ResumeLayout(false);
            poisonTabControl1.ResumeLayout(false);
            pageProcesses.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private TableLayoutPanel tableLayoutPanel2;
        private TableLayoutPanel tableLayoutPanel3;
        private ReaLTaiizor.Controls.ForeverButton btnSaveProcessSetting;
        private ReaLTaiizor.Controls.HopeButton btnAdd;
        private DataGridView dataGridView;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel5;
        private HopeButton btn_AddProcess;
        private ParrotGroupBox grpSetting;
        private ParrotGroupBox grpProcess;
        private SplitContainer splitContainer1;
        private PoisonTabControl poisonTabControl1;
        private System.Windows.Forms.TabPage pageProcesses;
        private System.Windows.Forms.TabPage pageLayout;
        private System.Windows.Forms.TabPage pageSetting;
        private System.Windows.Forms.TabPage pageCsv;
    }
}
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,510 @@
using LB_SmartVision.Forms.Pages.ProcessPage;
using LB_SmartVision.ProcessRun;
using LB_VisionControl;
using LB_VisionProcesses;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Collections.Concurrent;
using System.Data;
using System.Text;
using VisionControl.Forms;
namespace LB_SmartVision.Forms.Pages.SettingPage
{
    public partial class SettingEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        RunSettingPage RunSettingPage = new RunSettingPage();
        LayoutPage LayoutPage = new LayoutPage();
        CsvPage CsvPage = new CsvPage();
        public SettingEditPage()
        {
            Name = "SettingEditPage";
            Text = "流程设置";
            //this.Font = new Font("Microsoft YaHei UI", 16F, FontStyle.Regular, GraphicsUnit.Point, 0);
            InitializeComponent();
            dataGridView.DataError += new DataGridViewDataErrorEventHandler(dataGridView_DataError);
            pageSetting.Controls.Add(RunSettingPage);
            RunSettingPage.Dock = DockStyle.Fill;
            pageLayout.Controls.Add(LayoutPage);
            LayoutPage.Dock = DockStyle.Fill;
            pageCsv.Controls.Add(CsvPage);
            CsvPage.Dock = DockStyle.Fill;
        }
        private void SettingEditPage_Paint(object sender, PaintEventArgs e)
        {
            RunSettingPage.LoadFromJson();
            uiFlowLayoutPanel1.Controls.Clear();
            if (GlobalVar.dicProcesses.Count <= 0)
                return;
            // ä½¿ç”¨æ–¹å¼
            var sortedKeys = GlobalVar.dicProcesses.Keys
                .OrderBy(k => k, new NaturalStringComparer())
                .ToList();
            foreach (var key in sortedKeys)
            {
                string ProcessesName = key;
                string ProcessesOK = GlobalVar.dicProcesses[ProcessesName].Rate_OK.ToString() + "%";
                if (string.IsNullOrEmpty(ProcessesName) || string.IsNullOrEmpty(ProcessesOK))
                    return;
                UserItem flow = new UserItem(new string[] { "重命名", "移除" });
                flow.Name = ProcessesName;
                flow.Text = $"[{ProcessesOK}]";
                if (GlobalVar.dicProcesses[ProcessesName].Result)
                    flow.state = State.Pass;
                else
                    flow.state = State.Error;
                LoadFlowEvent(flow);
                uiFlowLayoutPanel1.Controls.Add(flow);
            }
            LoadData();
        }
        private void btn_AddProcess_Click(object sender, EventArgs e)
        {
            string Name = "流程" + GlobalVar.dicProcesses.Count;
            while (GlobalVar.dicProcesses.ContainsKey(Name))
                Name += "副本";
            if (string.IsNullOrEmpty(Name))
                return;
            int hashCode = GlobalVar.dicProcesses.GetHashCode();
            GlobalVar.dicProcesses.TryAdd(Name, new ProcessRunBll(Name, GlobalVar.dicCameras, GlobalVar.dicCommunicators));
            LogInfo?.Invoke(string.Format("添加流程[{0}]成功", Name), LogInfoType.PASS);
            this.Invalidate();
        }
        private void LoadFlowEvent(UserItem flow)
        {
            //按键1为重命名
            flow.MenuItem1ClickedEvent += RenameEvent;
            //按键2为移除
            flow.MenuItem2ClickedEvent += DeleteEvent;
        }
        private void RemoveFlowEvent(UserItem flow)
        {
            //按键1为重命名
            flow.MenuItem1ClickedEvent -= RenameEvent;
            //按键2为移除
            flow.MenuItem2ClickedEvent -= DeleteEvent;
        }
        /// <summary>
        /// é‡å‘½åæµç¨‹
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Text"></param>
        private void RenameEvent(string Name, string Text)
        {
            RenameForm renameForm = new RenameForm(Name);
            // è®¢é˜…事件
            renameForm.ShowDialog();
            if (!renameForm.bRename)
                return;
            if (GlobalVar.dicProcesses.ContainsKey(renameForm.strNewName))
            {
                MessageBox.Show("命名重复!", "异常");
                return;
            }
            for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
            {
                UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                string name = flow.Name;
                if (name != Name)
                    continue;
                flow.Name = renameForm.strNewName;
                string oldName = name;
                string newName = renameForm.strNewName;
                // é‡å‘½åå‰ä¿å­˜æµç¨‹
                if (GlobalVar.dicProcesses.ContainsKey(oldName)
                    && GlobalVar.dicProcesses[oldName].Save(out _))
                    GlobalVar.dicProcesses.TryRename(oldName, newName);
                flow.Refresh();
            }
        }
        /// <summary>
        /// ç§»é™¤æµç¨‹
        /// </summary>
        /// <param name="Name"></param>
        /// <param name="Text"></param>
        private void DeleteEvent(string Name, string Text)
        {
            if (uiFlowLayoutPanel1.Controls.Count <= 1)
            {
                MessageBox.Show("至少保留一个流程");
                return;
            }
            try
            {
                this.BeginInvoke(new Action(() =>
                {
                    for (int i = 0; i < uiFlowLayoutPanel1.Controls.Count; i++)
                    {
                        UserItem flow = (UserItem)uiFlowLayoutPanel1.Controls[i];
                        string name = flow.Name;
                        if (name != Name)
                            continue;
                        // æ‰§è¡Œé¢å¤–的逻辑,如确认删除或记录数据
                        DialogResult result = MessageBox.Show($"确定要删除[{name}]?该操作是不可恢复的", "删除确认", MessageBoxButtons.YesNoCancel);
                        // å¦‚果用户选择“否”,则取消删除操作
                        if (result == DialogResult.Yes)
                        {
                            RemoveFlowEvent(flow);
                            uiFlowLayoutPanel1.Controls.Remove(uiFlowLayoutPanel1.Controls[i]);
                            GlobalVar.dicProcesses.TryRemove(name, out ProcessRunBll ProcessRunBll);
                            string ProcessPath = GlobalVar.allProcessPath + name;
                            if (Directory.Exists(ProcessPath))
                                Directory.Delete(ProcessPath, true);
                        }
                    }
                }));
            }
            catch { }
        }
        private void LoadData()
        {
            dataGridView.AllowUserToAddRows = false;
            dataGridView.Columns.Clear();
            dataGridView.Rows.Clear();
            dataGridView.DataSource = null;
            // åˆ›å»ºå¸¦æœ‰ ComboBox çš„列
            DataGridViewComboBoxColumn comboBoxColumn0 = new DataGridViewComboBoxColumn();
            comboBoxColumn0.HeaderText = "流程名";
            comboBoxColumn0.Name = "TableName";
            comboBoxColumn0.Items.Add("无");
            foreach (var ProcessName in GlobalVar.dicProcesses.Keys)
                comboBoxColumn0.Items.Add(ProcessName);
            dataGridView.Columns.Add(comboBoxColumn0);
            // åˆ›å»ºå¸¦æœ‰ ComboBox çš„列
            DataGridViewComboBoxColumn comboBoxColumn1 = new DataGridViewComboBoxColumn();
            comboBoxColumn1.HeaderText = "触发通讯";
            comboBoxColumn1.Name = "TriggerComName";
            comboBoxColumn1.Items.Add("无");
            foreach (var ComName in GlobalVar.dicCommunicators.Keys)
                comboBoxColumn1.Items.Add(ComName);
            dataGridView.Columns.Add(comboBoxColumn1);
            // åˆ›å»ºæ™®é€šæ–‡æœ¬åˆ—
            dataGridView.Columns.Add("TriggerString", "触发字符");
            DataGridViewComboBoxColumn comboBoxColumn2 = new DataGridViewComboBoxColumn();
            comboBoxColumn2.HeaderText = "成功通讯";
            comboBoxColumn2.Name = "PassComName";
            comboBoxColumn2.Items.Add("无");
            foreach (var ComName in GlobalVar.dicCommunicators.Keys)
                comboBoxColumn2.Items.Add(ComName);
            dataGridView.Columns.Add(comboBoxColumn2);
            // åˆ›å»ºæ™®é€šæ–‡æœ¬åˆ—
            dataGridView.Columns.Add("PassString", "成功字符");
            DataGridViewComboBoxColumn comboBoxColumn3 = new DataGridViewComboBoxColumn();
            comboBoxColumn3.HeaderText = "失败通讯";
            comboBoxColumn3.Name = "ErrorComName";
            comboBoxColumn3.Items.Add("无");
            foreach (var ComName in GlobalVar.dicCommunicators.Keys)
                comboBoxColumn3.Items.Add(ComName);
            dataGridView.Columns.Add(comboBoxColumn3);
            dataGridView.Columns.Add("ErrorString", "失败字符");
            // åˆ›å»ºæ™®é€šæ–‡æœ¬åˆ—
            dataGridView.Columns.Add("RetestTimes", "重测次数");
            dataGridView.Columns.Add("ConnectProcess", "关联流程");
            // åˆ›å»ºå¸¦æœ‰ Button çš„列
            DataGridViewButtonColumn btnEditResult = new DataGridViewButtonColumn();
            btnEditResult.HeaderText = "关联结果";
            btnEditResult.Name = "ConnectResult";
            btnEditResult.Text = "未关联"; // æŒ‰é’®æ˜¾ç¤ºçš„æ–‡æœ¬
            btnEditResult.UseColumnTextForButtonValue = false; // ç¦ç”¨ç»Ÿä¸€æ–‡æœ¬
            dataGridView.Columns.Add(btnEditResult);
            foreach (var item in GlobalVar.dicProcessSetting.OrderBy(kvp => kvp.Key))
            {
                string ProcessName = item.Value["流程名"];
                string TriggerComName = item.Value["触发通讯"];
                string TriggerString = item.Value["触发字符"];
                string PassComName = item.Value["成功通讯"];
                string PassString = item.Value["成功字符"];
                string ErrorComName = item.Value["失败通讯"];
                string ErrorString = item.Value["失败字符"];
                string RetestTimes = item.Value["重测次数"];
                string ConnectProcess = item.Value["关联流程"];
                string ConnectResult = item.Value["关联结果"];
                if (string.IsNullOrEmpty(ConnectResult) || ConnectResult.Trim() == "")
                    ConnectResult = "未关联";
                if (!GlobalVar.dicCommunicators.ContainsKey(TriggerComName) && GlobalVar.dicCommunicators.Count > 0)
                {
                    if (TriggerComName != "无")
                        TriggerComName = GlobalVar.dicCommunicators.ElementAt(0).Key;
                    item.Value["触发通讯"] = TriggerComName;
                }
                if (!GlobalVar.dicCommunicators.ContainsKey(PassComName) && GlobalVar.dicCommunicators.Count > 0)
                {
                    if (PassComName != "无")
                        PassComName = GlobalVar.dicCommunicators.ElementAt(0).Key;
                    item.Value["成功通讯"] = PassComName;
                }
                if (!GlobalVar.dicCommunicators.ContainsKey(ErrorComName) && GlobalVar.dicCommunicators.Count > 0)
                {
                    if (ErrorComName != "无")
                        ErrorComName = GlobalVar.dicCommunicators.ElementAt(0).Key;
                    item.Value["失败通讯"] = ErrorComName;
                }
                // æ·»åŠ è¡Œå¹¶è®¾ç½®æŒ‰é’®æ–‡æœ¬
                int rowIndex = dataGridView.Rows.Add(
                    ProcessName,
                    TriggerComName,
                    TriggerString,
                    PassComName,
                    PassString,
                    ErrorComName,
                    ErrorString,
                    RetestTimes,
                    ConnectProcess
                );
                // å•独设置按钮列的值为ConnectRsult
                dataGridView.Rows[rowIndex].Cells["ConnectResult"].Value = ConnectResult;
            }
            //dataGridView.Columns["DBName"].ReadOnly = true;
        }
        private void dataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            // è®°å½•错误但不显示默认对话框
            e.ThrowException = false;
            //// å¯ä»¥è‡ªå®šä¹‰é”™è¯¯å¤„理
            //MessageBox.Show($"数据错误: {e.Exception.Message}", "错误",
            //              MessageBoxButtons.OK, MessageBoxIcon.Error);
            //// æˆ–者简单地忽略错误
            //e.Cancel = true;
        }
        private void dataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            int rowIndex = e.RowIndex;  // èŽ·å–ä¿®æ”¹çš„è¡Œç´¢å¼•
            int columnIndex = e.ColumnIndex;  // èŽ·å–ä¿®æ”¹çš„åˆ—ç´¢å¼•
            if (e.ColumnIndex == 0
                && dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] != null
                && dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] is DataGridViewComboBoxCell)
            {
                DataGridViewComboBoxCell cell =
                    dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewComboBoxCell;
                // æ¸…空原有选项
                cell.Items.Clear();
                foreach (var ProcessName in GlobalVar.dicProcesses.Keys)
                    cell.Items.Add(ProcessName);
            }
            if ((e.ColumnIndex == 1 || e.ColumnIndex == 3)
                && dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] != null
                && dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] is DataGridViewComboBoxCell)
            {
                DataGridViewComboBoxCell cell =
                    dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewComboBoxCell;
                // æ¸…空原有选项
                cell.Items.Clear();
                cell.Items.Add("无");
                foreach (var ComName in GlobalVar.dicCommunicators.Keys)
                    cell.Items.Add(ComName);
            }
        }
        private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            int rowIndex = e.RowIndex;  // èŽ·å–ä¿®æ”¹çš„è¡Œç´¢å¼•
            int columnIndex = e.ColumnIndex;  // èŽ·å–ä¿®æ”¹çš„åˆ—ç´¢å¼•
        }
        private void dataGridView_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            // èŽ·å–å½“å‰å³å°†è¢«åˆ é™¤çš„è¡Œçš„æ•°æ®
            DataGridViewRow rowToDelete = e.Row;
            // å‡è®¾æˆ‘们要检查第一列的数据
            string ProcessName = rowToDelete.Cells[0]?.Value?.ToString();
            // æ‰§è¡Œé¢å¤–的逻辑,如确认删除或记录数据
            DialogResult result = MessageBox.Show($"确定要删除?该操作是不可恢复的", "删除确认", MessageBoxButtons.YesNo);
            // å¦‚果用户选择“否”,则取消删除操作
            if (result == DialogResult.No)
            {
                e.Cancel = true;  // å–消删除操作
            }
            else
            {
                LogInfo?.Invoke(string.Format("流程[{0}]删除触发设置", ProcessName), LogInfoType.INFO);
                // å¦‚果需要,可以在这里执行删除前的额外处理
                GlobalVar.dicProcessSetting.TryRemove(e.Row.Index, out ConcurrentDictionary<string, string> dic);
            }
        }
        private void dataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                if (e.ColumnIndex == dataGridView.Columns["ConnectResult"].Index && e.RowIndex >= 0)
                {
                    // èŽ·å–å½“å‰è¡Œçš„æ•°æ®
                    string ProcessName = dataGridView.Rows[e.RowIndex].Cells["TableName"].Value?.ToString();
                    if (string.IsNullOrEmpty(ProcessName))
                        return;
                    ProcessOutputsSelectForm processOutputsSelectForm
                        = new ProcessOutputsSelectForm(GlobalVar.dicProcesses[ProcessName].dicInputsMapping, GlobalVar.dicProcesses[ProcessName].dicOutputsMapping);
                    processOutputsSelectForm.ShowDialog();
                    if (string.IsNullOrEmpty(processOutputsSelectForm.SelectedOutput))
                    {
                        (GlobalVar.dicProcessSetting[e.RowIndex])["关联结果"] = processOutputsSelectForm.SelectedOutput;
                        dataGridView.Rows[e.RowIndex].Cells["ConnectResult"].Value = processOutputsSelectForm.SelectedOutput;
                    }
                }
            }
            catch { }
        }
        private void btn_SaveProcessSetting_Click(object sender, EventArgs e)
        {
            GlobalVar.dicProcessSetting.Clear();
            foreach (DataGridViewRow row in dataGridView.Rows)
            {
                if (!row.IsNewRow && row.Cells.Count >= 3 && row.Cells[0].Value != null)
                {
                    ConcurrentDictionary<string, string> keyValuePairs = new ConcurrentDictionary<string, string>();
                    int i = 0;
                    i = 0;
                    string ProcessName = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 1;
                    string TriggerComName = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 2;
                    string TriggerString = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 3;
                    string PassComName = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 4;
                    string PassString = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 5;
                    string ErrorComName = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 6;
                    string ErrorString = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 7;
                    string RetestTimes = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 8;
                    string ConnectProcess = row.Cells[i].Value == null ? "" : row.Cells[i].Value.ToString();
                    i = 9;
                    string ConnectResult = row.Cells[i].Value == null ? "未关联" : row.Cells[i].Value.ToString();
                    keyValuePairs.TryAdd("流程名", ProcessName);
                    keyValuePairs.TryAdd("触发通讯", TriggerComName);
                    keyValuePairs.TryAdd("触发字符", TriggerString);
                    keyValuePairs.TryAdd("成功通讯", PassComName);
                    keyValuePairs.TryAdd("成功字符", PassString);
                    keyValuePairs.TryAdd("失败通讯", ErrorComName);
                    keyValuePairs.TryAdd("失败字符", ErrorString);
                    keyValuePairs.TryAdd("重测次数", RetestTimes);
                    keyValuePairs.TryAdd("关联流程", ConnectProcess);
                    keyValuePairs.TryAdd("关联结果", ConnectResult);
                    GlobalVar.dicProcessSetting.TryAdd(row.Index, keyValuePairs);
                }
            }
            if (!VisionForm.SaveAllProcessSetting())
            {
                MessageBox.Show("保存失败!", "异常");
                LogInfo?.Invoke(string.Format("保存流程失败"), LogInfoType.ERROR);
            }
            else
                LogInfo?.Invoke(string.Format("保存流程成功"), LogInfoType.PASS);
        }
        private void btn_Add_Click(object sender, EventArgs e)
        {
            string ProcessName = string.Empty;
            if (GlobalVar.dicProcesses.Count > 0)
                ProcessName = GlobalVar.dicProcesses.Keys.ToList()[0];
            ConcurrentDictionary<string, string> keyValuePairs = new ConcurrentDictionary<string, string>();
            string ComName = string.Empty;
            if (string.IsNullOrEmpty(ComName) && GlobalVar.dicCommunicators.Count > 0)
                ComName = GlobalVar.dicCommunicators.ElementAt(0).Key;
            keyValuePairs.TryAdd("流程名", ProcessName);
            keyValuePairs.TryAdd("触发通讯", ComName);
            keyValuePairs.TryAdd("触发字符", "TEST");
            keyValuePairs.TryAdd("成功通讯", ComName);
            keyValuePairs.TryAdd("成功字符", "WB_OK");
            keyValuePairs.TryAdd("失败通讯", ComName);
            keyValuePairs.TryAdd("失败字符", "WB_NG");
            keyValuePairs.TryAdd("重测次数", "0");
            keyValuePairs.TryAdd("关联流程", "");
            keyValuePairs.TryAdd("关联结果", "未关联");
            GlobalVar.dicProcessSetting.TryAdd(dataGridView.Rows.Count, keyValuePairs);
            LogInfo?.Invoke(string.Format("流程[{0}]新建触发设置", ProcessName), LogInfoType.INFO);
            LoadData();
        }
    }
}
LB_SmartVision/Forms/Pages/SettingPage/SettingEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,152 @@

using ReaLTaiizor.Controls;
namespace LB_SmartVision.Forms.Pages.UserManagementPage
{
    partial class UserManagementEditPage
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            btn_Add = new HopeButton();
            btn_Clear = new LostButton();
            uiFlowLayoutPanel1 = new FlowLayoutPanel();
            tableLayoutPanel1 = new TableLayoutPanel();
            tableLayoutPanel2 = new TableLayoutPanel();
            tableLayoutPanel1.SuspendLayout();
            tableLayoutPanel2.SuspendLayout();
            SuspendLayout();
            //
            // btn_Add
            //
            btn_Add.BorderColor = Color.FromArgb(220, 223, 230);
            btn_Add.ButtonType = ReaLTaiizor.Util.HopeButtonType.Primary;
            btn_Add.Cursor = Cursors.Hand;
            btn_Add.DangerColor = Color.FromArgb(245, 108, 108);
            btn_Add.DefaultColor = Color.FromArgb(255, 255, 255);
            btn_Add.Dock = DockStyle.Fill;
            btn_Add.Font = new Font("宋体", 12F);
            btn_Add.HoverTextColor = Color.FromArgb(48, 49, 51);
            btn_Add.InfoColor = Color.FromArgb(144, 147, 153);
            btn_Add.Location = new Point(503, 3);
            btn_Add.MinimumSize = new Size(1, 1);
            btn_Add.Name = "btn_Add";
            btn_Add.PrimaryColor = Color.FromArgb(64, 158, 255);
            btn_Add.Size = new Size(95, 38);
            btn_Add.SuccessColor = Color.FromArgb(103, 194, 58);
            btn_Add.TabIndex = 11;
            btn_Add.Text = "增加";
            btn_Add.TextColor = Color.White;
            btn_Add.WarningColor = Color.FromArgb(230, 162, 60);
            //
            // btn_Clear
            //
            btn_Clear.BackColor = Color.FromArgb(45, 45, 48);
            btn_Clear.Cursor = Cursors.Hand;
            btn_Clear.Dock = DockStyle.Fill;
            btn_Clear.Font = new Font("宋体", 12F);
            btn_Clear.ForeColor = Color.White;
            btn_Clear.HoverColor = Color.DodgerBlue;
            btn_Clear.Image = null;
            btn_Clear.Location = new Point(403, 3);
            btn_Clear.MinimumSize = new Size(1, 1);
            btn_Clear.Name = "btn_Clear";
            btn_Clear.Size = new Size(94, 38);
            btn_Clear.TabIndex = 12;
            btn_Clear.Text = "清除";
            //
            // uiFlowLayoutPanel1
            //
            uiFlowLayoutPanel1.BackColor = Color.FromArgb(32, 41, 50);
            uiFlowLayoutPanel1.Dock = DockStyle.Fill;
            uiFlowLayoutPanel1.Font = new Font("宋体", 12F);
            uiFlowLayoutPanel1.ForeColor = SystemColors.Control;
            uiFlowLayoutPanel1.Location = new Point(4, 5);
            uiFlowLayoutPanel1.Margin = new Padding(4, 5, 4, 5);
            uiFlowLayoutPanel1.MinimumSize = new Size(1, 1);
            uiFlowLayoutPanel1.Name = "uiFlowLayoutPanel1";
            uiFlowLayoutPanel1.Padding = new Padding(2);
            uiFlowLayoutPanel1.Size = new Size(599, 293);
            uiFlowLayoutPanel1.TabIndex = 10;
            uiFlowLayoutPanel1.Text = "`";
            //
            // tableLayoutPanel1
            //
            tableLayoutPanel1.ColumnCount = 1;
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20F));
            tableLayoutPanel1.Controls.Add(uiFlowLayoutPanel1, 0, 0);
            tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 1);
            tableLayoutPanel1.Dock = DockStyle.Fill;
            tableLayoutPanel1.Location = new Point(0, 0);
            tableLayoutPanel1.Name = "tableLayoutPanel1";
            tableLayoutPanel1.RowCount = 2;
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
            tableLayoutPanel1.Size = new Size(607, 353);
            tableLayoutPanel1.TabIndex = 13;
            //
            // tableLayoutPanel2
            //
            tableLayoutPanel2.ColumnCount = 6;
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 16.666666F));
            tableLayoutPanel2.Controls.Add(btn_Add, 5, 0);
            tableLayoutPanel2.Controls.Add(btn_Clear, 4, 0);
            tableLayoutPanel2.Dock = DockStyle.Fill;
            tableLayoutPanel2.Location = new Point(3, 306);
            tableLayoutPanel2.Name = "tableLayoutPanel2";
            tableLayoutPanel2.RowCount = 1;
            tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tableLayoutPanel2.Size = new Size(601, 44);
            tableLayoutPanel2.TabIndex = 11;
            //
            // UserManagementEditPage
            //
            BackColor = Color.FromArgb(32, 41, 50);
            Controls.Add(tableLayoutPanel1);
            ForeColor = SystemColors.Control;
            Name = "UserManagementEditPage";
            Size = new Size(607, 353);
            Paint += MESEditPage_Paint;
            tableLayoutPanel1.ResumeLayout(false);
            tableLayoutPanel2.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Controls.HopeButton btn_Add;
        private ReaLTaiizor.Controls.LostButton btn_Clear;
        private FlowLayoutPanel uiFlowLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel1;
        private TableLayoutPanel tableLayoutPanel2;
    }
}
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
using LB_VisionControl;
using OpenCvSharp.Flann;
using System;
using System.Collections.Concurrent;
using System.Windows.Forms;
using System.Xml.Linq;
namespace LB_SmartVision.Forms.Pages.UserManagementPage
{
    public partial class UserManagementEditPage : UserControl
    {
        public Action<string, LogInfoType> LogInfo;
        public UserManagementEditPage()
        {
            InitializeComponent();
            Name = "UserManagementEditPage";
            Text = "用户管理设置";
        }
        private void MESEditPage_Paint(object sender, PaintEventArgs e)
        {
            uiFlowLayoutPanel1.Controls.Clear();
        }
    }
}
LB_SmartVision/Forms/Pages/UserManagementPage/UserManagementEditPage.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/GlobalVar.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,124 @@
using LB_SmartVision.Forms.Pages.SettingPage;
using LB_SmartVision.ProcessRun;
using LB_SmartVision.Tool;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVision
{
    public enum LogInfoType { INFO, WARN, PASS, ERROR, NOSHOW }
    public class GlobalVar
    {
        static GlobalVar()
        {
            strApplicationPath = Application.StartupPath;
            strPathLog = Application.StartupPath + "生产日志\\" + DateTime.Now.ToString("yyyyMMdd");
            strPathCsv = Application.StartupPath + "生产数据\\" + DateTime.Now.ToString("yyyyMMdd");
            strStartTime = DateTime.Now.ToString("yyyyMMdd_HHmm");
        }
        /// <summary>
        /// æµç¨‹é›†åˆ(Key:流程名,Value:运行步骤集合)
        /// </summary>
        public static ObservableConcurrentDictionary<string, ProcessRunBll> dicProcesses { get; set; } = new ObservableConcurrentDictionary<string, ProcessRunBll>();
        /// <summary>
        /// ç›¸æœºé›†åˆ(Key:相机SN,Value:相机句柄)
        /// </summary>
        public static ObservableConcurrentDictionary<string, BaseCamera> dicCameras { get; set; } = new ObservableConcurrentDictionary<string, BaseCamera>();
        /// <summary>
        /// é€šè®¯é›†åˆ(Key:通讯名,Value:通讯句柄)
        /// </summary>
        public static ObservableConcurrentDictionary<string, BaseCommunicator> dicCommunicators { get; set; } = new ObservableConcurrentDictionary<string, BaseCommunicator>();
        /// <summary>
        /// è§¦å‘流程设置集合
        /// </summary>
        public static ConcurrentDictionary<int, ConcurrentDictionary<string, string>> dicProcessSetting { get; set; } = new ConcurrentDictionary<int, ConcurrentDictionary<string, string>>();
        /// <summary>
        /// å¸ƒå±€é›†åˆ
        /// </summary>
        public static ConcurrentDictionary<int, Layout> dicLayout { get; set; } = new ConcurrentDictionary<int, Layout>();
        /// <summary>
        /// è¡¨æ ¼é›†åˆ
        /// </summary>
        public static ConcurrentDictionary<string, CsvSetting> dicCsvSetting { get; set; } = new ConcurrentDictionary<string, CsvSetting>();
        public static string allProcessConnectionStringPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_ProcessConnections.json";
        #region ç›¸æœº
        public static ConcurrentDictionary<string, string> allCamerasConnectionString = new ConcurrentDictionary<string, string>();
        public static string allCamerasConnectionStringPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_CameraConnections.json";
        #endregion
        #region é€šè®¯å£
        public static ConcurrentDictionary<string, string> allCommunicatorsConnectionString = new ConcurrentDictionary<string, string>();
        public static string allCommunicatorsConnectionStringPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_CommunicatorConnections.json";
        #endregion
        #region æµç¨‹
        public static Dictionary<string, object> ControlStates { get; set; } = new Dictionary<string, object>();
        public static string allProcessPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\";
        public static string allProcessSettingStringPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_ProcessSettings.json";
        public static string allRunSettingStringPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_RunSettings.json";
        public static string allProcessVarsPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_ProcessVars.json";
        public static string allLayoutPath
             => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_AllLayout.json";
        public static string allCsvPath
            => GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\A_AllCsv.json";
        #endregion
        /// <summary>
        /// è½¯ä»¶è·¯å¾„
        /// </summary>
        public static string strApplicationPath = Application.StartupPath;
        /// <summary>
        /// äº§å“åç§°
        /// </summary>
        public static string strProductName = "产品0";
        /// <summary>
        /// å­˜å‚¨æ—¥å¿—路径
        /// </summary>
        public static string strPathLog = Application.StartupPath + "生产日志\\" + DateTime.Now.ToString("yyyyMMdd");
        /// <summary>
        /// å­˜å‚¨æ—¥å¿—路径
        /// </summary>
        public static string strPathCsv = Application.StartupPath + "生产数据\\" + DateTime.Now.ToString("yyyyMMdd");
        /// <summary>
        /// è½¯ä»¶å¼€å¯æ—¥æœŸ
        /// </summary>
        public static string strStartTime = string.Empty;
    }
}
LB_SmartVision/LB_Collections.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,223 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVision
{
    [Serializable]
    public class LB_Collections<T> : ICollection<CollectionItem<T>>
    {
        private List<CollectionItem<T>> _items = new List<CollectionItem<T>>();
        // é€šè¿‡åç§°æŸ¥æ‰¾
        public CollectionItem<T> Get(string name)
        {
            var item = _items.FirstOrDefault(item => item.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
            if (item == null)
                return default;
            return item;
        }
        // é€šè¿‡ç´¢å¼•查找
        public CollectionItem<T> Get(int index)
        {
            var item = _items.FirstOrDefault(item => item.Index == index);
            if (item == null)
                return default;
            return item;
        }
        // ICollection<NamedItem<T>> å®žçް
        public int Count => _items.Count;
        public bool IsReadOnly => false;
        void ICollection<CollectionItem<T>>.Add(CollectionItem<T> item)
        {
            var existingItem = Get(item.Name);
            if (existingItem != null)
            {
                // å¦‚果已存在,更新现有项的值
                existingItem = item;
            }
            else
            {
                // å¦‚果不存在,创建新项并分配索引
                _items.Add(item);
            }
            // æ›´æ–°åŽè‡ªåŠ¨æŽ’åº
            SortItems();
        }
        // æ·»åŠ é¡¹æ—¶ä¸ºæ–°é¡¹åˆ†é…ä¸€ä¸ªç´¢å¼•
        public void Add(string name, T value)
        {
            var existingItem = Get(name);
            if (existingItem != null)
            {
                // å¦‚果已存在,更新现有项的值
                existingItem.Value = value;
            }
            else
            {
                // å¦‚果不存在,创建新项并分配索引
                var newItem = new CollectionItem<T>(name, _items.Count > 0 ? _items.Max(i => i.Index) + 1 : 0, value);
                _items.Add(newItem);
            }
            // æ›´æ–°åŽè‡ªåŠ¨æŽ’åº
            SortItems();
        }
        // æŒ‰ Index æŽ’序集合
        private void SortItems()
        {
            _items = _items.OrderBy(item => item.Index).ToList();
        }
        // é€šè¿‡ç´¢å¼•器实现基于序号的访问
        public T this[int index]
        {
            get
            {
                if (index < 0 || index >= _items.Count)
                {
                    return default;
                }
                return _items[index].Value;
            }
            set
            {
                if (index < 0 || index >= _items.Count)
                {
                    return;
                }
                _items[index].Value = value;
            }
        }
        public T this[string name]
        {
            get
            {
                var existingItem = Get(name);
                if (existingItem != null)
                {
                    // å¦‚果已存在,更新现有项的值
                    return existingItem.Value;
                }
                return default;
            }
            set
            {
                var item = _items.FirstOrDefault(i => i.Name == name);
                if (item != null)
                {
                    item.Value = value;
                }
            }
        }
        public void Clear()
        {
            _items.Clear();
            _items.TrimExcess(); // å°†å®¹é‡ç¼©å‡åˆ°å®žé™…元素数量
        }
        public bool Contains(CollectionItem<T> item)
        {
            return _items.Contains(item);
        }
        public bool Contains(string name)
        {
            var item = _items.FirstOrDefault(i => i.Name == name);
            if (item != null)
                return true;
            return false;
        }
        public void CopyTo(CollectionItem<T>[] array, int arrayIndex)
        {
            _items.CopyTo(array, arrayIndex);
        }
        public bool Remove(CollectionItem<T> item)
        {
            var removed = _items.Remove(item);
            if (removed)
            {
                // ç§»é™¤å…ƒç´ åŽï¼Œè°ƒæ•´åŽç»­å…ƒç´ çš„索引
                UpdateIndexes();
            }
            return removed;
        }
        public IEnumerator<CollectionItem<T>> GetEnumerator()
        {
            return _items.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return _items.GetEnumerator();
        }
        // é€šè¿‡åç§°åˆ é™¤
        public bool Remove(string name)
        {
            var namedItem = Get(name);
            if (namedItem != null)
            {
                return Remove(namedItem);
            }
            return false;
        }
        // é€šè¿‡ç´¢å¼•删除
        public bool Remove(int index)
        {
            var namedItem = Get(index);
            if (namedItem != null)
            {
                return Remove(namedItem);
            }
            return false;
        }
        // åˆ é™¤é¡¹åŽï¼Œè°ƒæ•´å…¶ä»–项的索引
        private void UpdateIndexes()
        {
            for (int i = 0; i < _items.Count; i++)
            {
                _items[i].Index = i;
            }
        }
    }
    public class CollectionItem<T>
    {
        public string Name { get; set; }
        public int Index { get; set; }
        public T Value { get; set; }       // å­˜å‚¨çš„对象
        public CollectionItem(string name, int index, T value)
        {
            Name = name;
            Index = index;
            Value = value;
        }
        public override string ToString()
        {
            return $"{Name} (Index: {Index}, Value: {Value})";
        }
    }
}
LB_SmartVision/LB_SmartVision.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <ApplicationIcon>logo.ico</ApplicationIcon>
  </PropertyGroup>
  <ItemGroup>
    <Content Include="logo.ico" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\LB_VisionControl\LB_VisionControl.csproj" />
    <ProjectReference Include="..\LB_VisionFlowNode\LB_VisionFlowNode.csproj" />
    <ProjectReference Include="..\LB_VisionProcesses\LB_VisionProcesses.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Compile Update="Properties\Resources.Designer.cs">
      <DesignTime>True</DesignTime>
      <AutoGen>True</AutoGen>
      <DependentUpon>Resources.resx</DependentUpon>
    </Compile>
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Update="Properties\Resources.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>
  <ItemGroup>
    <Folder Include="Forms\Pages\CameraPage\" />
    <Folder Include="Forms\Pages\CommunicatorPage\" />
    <Folder Include="Forms\Pages\ProcessPage\" />
    <Folder Include="Forms\Pages\SettingPage\" />
    <Folder Include="ref\" />
    <Folder Include="ProcessRun\" />
    <Folder Include="Tool\" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="MaterialSkin.NET5" Version="1.0.2" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="halcondotnet">
      <HintPath>ref\halcondotnet.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>
LB_SmartVision/LB_SmartVision.sln
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,67 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36804.6
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_SmartVision", "LB_SmartVision.csproj", "{BE6C1F96-7C34-4379-A819-D1E31CBF275C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_VisionControl", "..\LB_VisionControl\LB_VisionControl.csproj", "{09034C42-D16D-4DD4-8768-051463A2C026}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_VisionFlowNode", "..\LB_VisionFlowNode\LB_VisionFlowNode.csproj", "{5DF26C1E-07F7-4515-9855-78FE7C03E502}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_VisionProcesses", "..\LB_VisionProcesses\LB_VisionProcesses.csproj", "{A5B2996F-F417-40AE-A405-E39A8C71FFB3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_SmartVisionCommon", "..\LB_SmartVisionCommon\LB_SmartVisionCommon.csproj", "{3B0FE686-8AE4-4DFC-B14E-8794AE4557D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_SmartVisionCameraDevice", "..\LB_SmartVisionCameraDevice\LB_SmartVisionCameraDevice.csproj", "{71FCC813-7297-4A75-830B-2ACB3EFF5498}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_SmartVisionCameraSDK", "..\LB_SmartVisionCameraSDK\LB_SmartVisionCameraSDK.csproj", "{6F4E5C61-CBA5-7DBA-018F-ADC56077E837}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LB_SmartVisionLoginUI", "..\LB_SmartVisionLoginUI\LB_SmartVisionLoginUI.csproj", "{6E8B08CC-DA76-415E-ABCA-165DA62F72CB}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Release|Any CPU = Release|Any CPU
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {BE6C1F96-7C34-4379-A819-D1E31CBF275C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {BE6C1F96-7C34-4379-A819-D1E31CBF275C}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {BE6C1F96-7C34-4379-A819-D1E31CBF275C}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {BE6C1F96-7C34-4379-A819-D1E31CBF275C}.Release|Any CPU.Build.0 = Release|Any CPU
        {09034C42-D16D-4DD4-8768-051463A2C026}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {09034C42-D16D-4DD4-8768-051463A2C026}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {09034C42-D16D-4DD4-8768-051463A2C026}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {09034C42-D16D-4DD4-8768-051463A2C026}.Release|Any CPU.Build.0 = Release|Any CPU
        {5DF26C1E-07F7-4515-9855-78FE7C03E502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {5DF26C1E-07F7-4515-9855-78FE7C03E502}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {5DF26C1E-07F7-4515-9855-78FE7C03E502}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {5DF26C1E-07F7-4515-9855-78FE7C03E502}.Release|Any CPU.Build.0 = Release|Any CPU
        {A5B2996F-F417-40AE-A405-E39A8C71FFB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {A5B2996F-F417-40AE-A405-E39A8C71FFB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {A5B2996F-F417-40AE-A405-E39A8C71FFB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {A5B2996F-F417-40AE-A405-E39A8C71FFB3}.Release|Any CPU.Build.0 = Release|Any CPU
        {3B0FE686-8AE4-4DFC-B14E-8794AE4557D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {3B0FE686-8AE4-4DFC-B14E-8794AE4557D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {3B0FE686-8AE4-4DFC-B14E-8794AE4557D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {3B0FE686-8AE4-4DFC-B14E-8794AE4557D4}.Release|Any CPU.Build.0 = Release|Any CPU
        {71FCC813-7297-4A75-830B-2ACB3EFF5498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {71FCC813-7297-4A75-830B-2ACB3EFF5498}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {71FCC813-7297-4A75-830B-2ACB3EFF5498}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {71FCC813-7297-4A75-830B-2ACB3EFF5498}.Release|Any CPU.Build.0 = Release|Any CPU
        {6F4E5C61-CBA5-7DBA-018F-ADC56077E837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {6F4E5C61-CBA5-7DBA-018F-ADC56077E837}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {6F4E5C61-CBA5-7DBA-018F-ADC56077E837}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {6F4E5C61-CBA5-7DBA-018F-ADC56077E837}.Release|Any CPU.Build.0 = Release|Any CPU
        {6E8B08CC-DA76-415E-ABCA-165DA62F72CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {6E8B08CC-DA76-415E-ABCA-165DA62F72CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {6E8B08CC-DA76-415E-ABCA-165DA62F72CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {6E8B08CC-DA76-415E-ABCA-165DA62F72CB}.Release|Any CPU.Build.0 = Release|Any CPU
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
        SolutionGuid = {2504174A-303B-40F7-9968-2DB03D8B58D5}
    EndGlobalSection
EndGlobal
LB_SmartVision/LB_SqlCommand.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,573 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVision
{
    public class LB_SqlCommand
    {
        /// <summary>
        /// è¿žæŽ¥å­—符串:指定 SQL Server å®žä¾‹å’Œæ•°æ®åº“(实际会读取dll.config中的值来更新连接字符串)
        /// </summary>
        public static string ConnectionString = "Data Source=localhost;Initial Catalog=master;Integrated Security=True;";
        /// <summary>
        /// åˆ¤æ–­æŒ‡å®šåˆ—是否存在某值
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="columnName">指定列名</param>
        /// <param name="value">指定值</param>
        /// <param name="connectionString"></param>
        /// <returns>值存在True</returns>
        public static bool IsExist(string tableName, string columnName, string value, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
            string sqlQuery = string.Format("SELECT CASE WHEN EXISTS (SELECT 1 FROM [{0}] " +
                "WHERE [{1}] = @Value) THEN 1 ELSE 0 END", tableName, columnName);
            // åˆ›å»º SQL è¿žæŽ¥
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                // åˆ›å»º SQL å‘½ä»¤
                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    // æ·»åŠ å‚æ•°ï¼Œé˜²æ­¢ SQL æ³¨å…¥
                    command.Parameters.AddWithValue("@Value", value);
                    // æ‰“开连接
                    connection.Open();
                    // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
                    int result = (int)command.ExecuteScalar();
                    // å¦‚æžœ result == 1,表示存在该值;否则不存在
                    if (result == 1)
                        return true;
                    else
                        return false;
                }
            }
        }
        /// <summary>
        /// åˆ¤æ–­æŒ‡å®šè¡¨æ˜¯å¦å­˜åœ¨
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="connectionString"></param>
        /// <returns>值存在True</returns>
        public static bool IsExistTable(string tableName, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
            string sqlQuery = $@"
            SELECT COUNT(*)
            FROM INFORMATION_SCHEMA.TABLES
            WHERE TABLE_NAME = @TableName";
            // åˆ›å»º SQL è¿žæŽ¥
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                // åˆ›å»º SQL å‘½ä»¤
                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    // æ·»åŠ è¡¨åå‚æ•°
                    command.Parameters.AddWithValue("@TableName", tableName);
                    // æ‰“开连接
                    connection.Open();
                    // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
                    int result = (int)command.ExecuteScalar();
                    // å¦‚æžœ result > 0,表示存在该表;否则不存在
                    if (result > 0)
                        return true;
                    else
                        return false;
                }
            }
        }
        /// <summary>
        /// é‡å‘½åè¡¨
        /// </summary>
        /// <param name="oldTableName"></param>
        /// <param name="newTableName"></param>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static bool RenameTable(string oldTableName, string newTableName, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            if (!IsExistTable(oldTableName))
                return false;
            // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
            string sqlQuery = $"EXEC sp_rename '{oldTableName}', '{newTableName}'"; ;
            // åˆ›å»º SQL è¿žæŽ¥
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                // åˆ›å»º SQL å‘½ä»¤
                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    // æ‰“开连接
                    connection.Open();
                    // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
                    int result = (int)command.ExecuteNonQuery();
                    // å¦‚æžœ result == -1,表示重命名成功
                    if (result == -1)
                        return true;
                    else
                        return false;
                }
            }
        }
        /// <summary>
        /// åˆ¤æ–­æŒ‡å®šè¡¨æ˜¯å¦å­˜åœ¨
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="connectionString"></param>
        /// <returns>值存在True</returns>
        public static bool DeleteTable(string tableName, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
            string sqlQuery = $"DROP TABLE IF EXISTS [{tableName}]";
            // åˆ›å»º SQL è¿žæŽ¥
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                // åˆ›å»º SQL å‘½ä»¤
                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    // æ‰“开连接
                    connection.Open();
                    // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
                    int result = (int)command.ExecuteNonQuery();
                    // å¦‚æžœ result = -1,表示存在该表移除成功
                    if (result == -1)
                        return true;
                    else
                        return false;
                }
            }
        }
        /// <summary>
        /// èŽ·å–æ‰€éœ€çš„å€¼é€šè¿‡ç´¢å¼•æŒ‡å®šåˆ—çš„æŒ‡å®šå€¼å®šä½åˆ°æ‰€åœ¨è¡Œçš„æŒ‡å®šåˆ—
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="indexName">指定列名</param>
        /// <param name="indexValue">指定列值</param>
        /// <param name="columnName">所需值的列名</param>
        /// <param name="connectionString"></param>
        /// <returns>所需列值</returns>
        public static string FindValueFromIndexName(string tableName, string indexName, string indexValue, string columnName, string connectionString = "")
        {
            try
            {
                if (string.IsNullOrEmpty(connectionString))
                    connectionString = ConnectionString;
                // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
                string sqlQuery = $"SELECT {columnName} FROM [{tableName}] WHERE {indexName} = @IndexValue";
                string resultValue = string.Empty;
                // è¿žæŽ¥æ•°æ®åº“并执行查询
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                    {
                        // æ·»åŠ å‚æ•°ä»¥é˜²æ­¢ SQL æ³¨å…¥
                        command.Parameters.AddWithValue("@IndexValue", indexValue);
                        // æ‰“开连接
                        connection.Open();
                        // æ‰§è¡ŒæŸ¥è¯¢å¹¶èŽ·å–ç»“æžœ
                        var result = command.ExecuteScalar();
                        if (result != null)
                        {
                            resultValue = result.ToString();
                        }
                    }
                }
                return resultValue;
            }
            catch { return string.Empty; }
        }
        /// <summary>
        /// åˆ é™¤æŒ‡å®šè¡Œé€šè¿‡ç´¢å¼•指定列的指定值
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="indexName">指定列名</param>
        /// <param name="indexValue">指定列值</param>
        /// <param name="connectionString"></param>
        /// <returns>删除成功True</returns>
        public static bool DeleteRowFromIndexName(string tableName, string indexName, string indexValue, string connectionString = "")
        {
            try
            {
                if (string.IsNullOrEmpty(connectionString))
                    connectionString = ConnectionString;
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    // åˆ é™¤æŒ‡å®šè¡Œ
                    string deleteQuery = string.Format("DELETE FROM [{0}] WHERE {1} = @indexValue", tableName, indexName);
                    using (SqlCommand cmd = new SqlCommand(deleteQuery, conn))
                    {
                        cmd.Parameters.AddWithValue("@indexValue", indexValue);
                        cmd.ExecuteNonQuery();
                    }
                    // æ›´æ–°å‰©ä½™è¡Œçš„ step
                    string updateQuery = string.Format(@"
                WITH OrderedSteps AS (
                    SELECT {1}, ROW_NUMBER() OVER (ORDER BY {1}) AS NewValue
                    FROM [{0}]
                )
                UPDATE [{0}]
                SET {1} = NewValue
                FROM [{0}] s
                JOIN OrderedSteps o ON s.{1} = o.{1};
            ", tableName, indexName);
                    using (SqlCommand cmd = new SqlCommand(updateQuery, conn))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    return true;
                }
            }
            catch { return false; }
        }
        /// <summary>
        /// äº¤æ¢æŒ‡å®šè¡Œçš„æ‰€æœ‰å€¼é€šè¿‡ç´¢å¼•指定列的指定值
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="swapName">列名</param>
        /// <param name="swapValue1">交换的列值</param>
        /// <param name="swapValue2">被交换的列值</param>
        /// <param name="connectionString"></param>
        /// <returns>交换成功True</returns>
        public static bool SwapRowFromIndexName(string tableName, string swapName, string swapValue1, string swapValue2, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
                // å¼€å§‹äº‹åŠ¡
                SqlTransaction transaction = conn.BeginTransaction();
                try
                {
                    // äº¤æ¢ step ä¸º 3 å’Œ 4 çš„行
                    string swapQuery = string.Format(@"
                        BEGIN TRANSACTION;
                        UPDATE [{0}]
                        SET {1} = @SwapTempValue
                        WHERE {1} = @SwapValue1;
                        UPDATE [{0}]
                        SET {1} = @SwapValue1
                        WHERE {1} = @SwapValue2;
                        UPDATE [{0}]
                        SET {1} = @SwapValue2
                        WHERE {1} = @SwapTempValue;
                        COMMIT;", tableName, swapName);
                    using (SqlCommand cmd = new SqlCommand(swapQuery, conn, transaction))
                    {
                        // æ·»åŠ å‚æ•°
                        cmd.Parameters.AddWithValue("@SwapValue1", swapValue1);
                        cmd.Parameters.AddWithValue("@SwapValue2", swapValue2);
                        cmd.Parameters.AddWithValue("@SwapTempValue", Guid.NewGuid().ToString());
                        // æ‰§è¡ŒæŸ¥è¯¢
                        cmd.ExecuteNonQuery();
                    }
                    // æäº¤äº‹åŠ¡
                    transaction.Commit();
                    return true;
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("交换失败,原因是:" + ex.Message.ToString());
                    // å‡ºçŽ°å¼‚å¸¸æ—¶å›žæ»šäº‹åŠ¡
                    transaction.Rollback();
                    return false;
                }
            }
        }
        /// <summary>
        /// æ›´æ–°æŒ‡å®šåˆ—的值通过索引指定列的指定值
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="oriValue"></param>
        /// <param name="newValue"></param>
        /// <param name="columnName"></param>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static bool UpdataValueFromIndexName(string tableName, string oriValue, string newValue, string columnName, string connectionString = "")
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            // SQL æŸ¥è¯¢è¯­å¥ï¼Œæ£€æŸ¥ ProcessName åˆ—是否存在指定的值
            string sqlQuery = string.Format("UPDATE [{0}] SET {1} = @NewValue WHERE {1} = @OriValue", tableName, columnName);
            string resultValue = string.Empty;
            // è¿žæŽ¥æ•°æ®åº“并执行查询
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                using (SqlCommand command = new SqlCommand(sqlQuery, connection))
                {
                    // å‚数化查询,防止 SQL æ³¨å…¥
                    command.Parameters.AddWithValue("@OriValue", oriValue);  // è¦æ›¿æ¢çš„原始值
                    command.Parameters.AddWithValue("@NewValue", newValue);  // æ›¿æ¢åŽçš„æ–°å€¼
                    // æ‰“开连接
                    connection.Open();
                    // æ‰§è¡Œæ›´æ–°æ“ä½œ
                    int rowsAffected = command.ExecuteNonQuery();
                    if (rowsAffected > 0)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// æ£€æŸ¥æ•°æ®åº“是否存在
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="databaseName"></param>
        /// <returns></returns>
        public static bool DatabaseExists(string connectionString, string databaseName)
        {
            string query = "SELECT database_id FROM sys.databases WHERE name = @databaseName";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(query, connection))
                {
                    command.Parameters.AddWithValue("@databaseName", databaseName);
                    var result = command.ExecuteScalar();
                    return result != null;
                }
            }
        }
        /// <summary>
        /// åˆ›å»ºæ•°æ®åº“(需要master权限)
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="databaseName"></param>
        /// <param name="databasePath"></param>
        /// <param name="logFilePath"></param>
        public static bool CreateDatabase(string connectionString, string databaseName)
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            if (!connectionString.Contains("master"))
                return false;
            try
            {
                string createQuery = $@"CREATE DATABASE {databaseName}";
                using (SqlConnection connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    using (SqlCommand command = new SqlCommand(createQuery, connection))
                    {
                        command.ExecuteNonQuery();
                    }
                }
                return true;
            }
            catch { return false; }
        }
        /// <summary>
        /// åˆ é™¤æ•°æ®åº“(需要master权限)
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <param name="connectionString"></param>
        /// <returns>值存在True</returns>
        public static bool DeleteDatabase(string databaseName, string connectionString)
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            if (!connectionString.Contains("master"))
                return false;
            // è®¾ç½® SQL DROP DATABASE è¯­å¥
            string dropDatabaseQuery = $"DROP DATABASE IF EXISTS {databaseName}";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                try
                {
                    // æ‰“开数据库连接
                    connection.Open();
                    // 1. è®¾ç½®æ•°æ®åº“为单用户模式,强制断开所有连接
                    string setSingleUserQuery = $@"ALTER DATABASE [{databaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;";
                    using (var cmd = new SqlCommand(setSingleUserQuery, connection))
                    {
                        cmd.ExecuteNonQuery();
                        Debug.WriteLine($"Database {databaseName} is now in single-user mode.");
                    }
                    // åˆ›å»º MySqlCommand å¯¹è±¡
                    using (SqlCommand cmd = new SqlCommand(dropDatabaseQuery, connection))
                    {
                        // æ‰§è¡Œåˆ é™¤æ•°æ®åº“操作
                        cmd.ExecuteNonQuery();
                        Debug.WriteLine("Database dropped successfully.");
                        return true;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("Error: " + ex.Message);
                    return false;
                }
            }
        }
        /// <summary>
        /// å¤åˆ¶è¡¨ç»“构和数据(需要master权限)
        /// </summary>
        /// <param name="connectionString"></param>
        /// <param name="sourceDatabase"></param>
        /// <param name="targetDatabase"></param>
        public static bool CopyDatabaseData(string connectionString, string sourceDatabase, string targetDatabase)
        {
            if (string.IsNullOrEmpty(connectionString))
                connectionString = ConnectionString;
            if (!connectionString.Contains("master"))
                return false;
            try
            {
                using (var connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    string useSourceDb = $"USE {sourceDatabase};";
                    string useTargetDb = $"USE {targetDatabase};";
                    // åˆ‡æ¢åˆ°æºæ•°æ®åº“
                    using (var cmd = new SqlCommand(useSourceDb, connection))
                    {
                        cmd.ExecuteNonQuery();
                    }
                    // èŽ·å–æºæ•°æ®åº“ä¸­æ‰€æœ‰è¡¨çš„åˆ—è¡¨
                    string getTablesQuery = "SELECT name FROM sys.tables;";
                    using (var cmd = new SqlCommand(getTablesQuery, connection))
                    {
                        // ä½¿ç”¨ CommandBehavior.CloseConnection è‡ªåŠ¨å…³é—­è¿žæŽ¥
                        using (var reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
                        {
                            while (reader.Read())
                            {
                                string tableName = reader.GetString(0);
                                Debug.WriteLine($"复制表: {tableName}");
                                // å¤åˆ¶è¡¨ç»“æž„
                                string createTableQuery = $"SELECT * INTO {targetDatabase}.dbo.{tableName} FROM {sourceDatabase}.dbo.{tableName} WHERE 1 = 0;";
                                using (var cmdCreateTable = new SqlCommand(createTableQuery, connection))
                                {
                                    cmdCreateTable.ExecuteNonQuery();
                                }
                                // å¤åˆ¶è¡¨æ•°æ®
                                string insertDataQuery = $"INSERT INTO {targetDatabase}.dbo.{tableName} SELECT * FROM {sourceDatabase}.dbo.{tableName};";
                                using (var cmdInsertData = new SqlCommand(insertDataQuery, connection))
                                {
                                    cmdInsertData.ExecuteNonQuery();
                                }
                            }
                        }
                    }
                }
                return true;
            }
            catch { return false; }
        }
        public static List<string> GetUserDatabases()
        {
            List<string> databases = new List<string>();
            string connectionString = "Server=localhost;Database=master;Integrated Security=True;";
            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                try
                {
                    connection.Open();
                    string query = @"
                        SELECT name
                        FROM sys.databases
                        WHERE database_id > 4 -- è¿‡æ»¤ç³»ç»Ÿæ•°æ®åº“
                            AND name NOT IN ('model','msdb','tempdb','DWConfiguration','DWDiagnostics','DWQueue')
                            AND source_database_id IS NULL -- æŽ’除数据库快照";
                    using (SqlCommand command = new SqlCommand(query, connection))
                    using (SqlDataReader reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            databases.Add(reader["name"]?.ToString());
                        }
                    }
                }
                catch (SqlException ex)
                {
                    Debug.WriteLine($"数据库查询失败: {ex.Message}");
                }
            }
            return databases;
        }
    }
}
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantoushangfangxiangshang.png
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouxiafangxiangxia.png
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouyoufangxiangyou.png
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-jiantouzuofangxiangzuo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-xinzengxinzeng.png
LB_SmartVision/LOGO/icon_7brki18x2r3/a-mti-zhuangtailoudou.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-APPjianpan.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-bangzhuzhongxin.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-caogaoxiang.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-chakanxiangqing.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-chexiao.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-duihao.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-fangkongquanpeizhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-fuzhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-gengduo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanbi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guankongpeizhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanlian.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-guanzhu.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jia.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jian.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantoushang.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouxia.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouyou-1.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouyou.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouzuo-1.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiantouzuo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jiemi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jieshu.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-jinzhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-mima.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pinglun.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pizhu.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-pizhuxinxi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-qidongyujing.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-qiehuan.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shaixuan.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shanchu.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shangchuan.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shezhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shipinpeizhi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shousuo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shouzhe.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuangjiantouyou.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuangjiantouzuo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-shuaxin.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-sousuo.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuisong.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuisongjilu.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-tuozhuaizhongxin.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-weiguanlian.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-xiazai.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhankai.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhiding.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-zhongqi.png
LB_SmartVision/LOGO/icon_7brki18x2r3/mti-ziyuanpeizhi.png
LB_SmartVision/LOGO/logo.ico
LB_SmartVision/ProcessRun/ExpressionTreeMappingEngine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,362 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Concurrent;
using System.Diagnostics;
using LB_VisionProcesses;
namespace LB_SmartVision.ProcessRun
{
    public class ExpressionTreeMappingEngine
    {
        private ConcurrentDictionary<string, List<Action<IProcess>>> _compiledMappings;
        private readonly ConcurrentDictionary<string, IProcess> _processContext;
        public ExpressionTreeMappingEngine(ConcurrentDictionary<string, IProcess> processContext)
        {
            _processContext = processContext;
            _compiledMappings = new ConcurrentDictionary<string, List<Action<IProcess>>>();
        }
        public void CompileMappings(ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping)
        {
            foreach (var processMapping in dicInputsMapping)
            {
                var processName = processMapping.Key;
                var actions = new List<Action<IProcess>>();
                foreach (var tuple in processMapping.Value)
                {
                    if (string.IsNullOrEmpty(tuple.Item2?.Trim()))
                        continue;
                    var action = CreateMappingAction(tuple.Item1, tuple.Item2);
                    if (action != null)
                        actions.Add(action);
                }
                _compiledMappings[processName] = actions;
            }
        }
        private Action<IProcess> CreateMappingAction(string inputPath, string outputPath)
        {
            try
            {
                // è§£æžè¾“入路径:TargetProcess.InputType.InputProperty
                var inputParts = inputPath.Split('.');
                if (inputParts.Length < 3) return null;
                string targetProcessName = inputParts[0];
                string inputType = inputParts[1]; // é€šå¸¸æ˜¯ "Inputs"
                string inputProperty = inputParts[2];
                // è§£æžè¾“出路径:SourceProcess.OutputType.OutputProperty
                var outputParts = outputPath.Split('.');
                if (outputParts.Length < 2) return null;
                string sourceProcessName = outputParts[0];
                string outputType = outputParts[1]; // "Inputs" æˆ– "Outputs"
                string outputProperty = outputParts.Length == 3 ? outputParts[2] : "";
                // åˆ›å»ºè¡¨è¾¾å¼å‚æ•°
                var targetParameter = Expression.Parameter(typeof(IProcess), "targetProcess");
                // æž„建获取源值的表达式
                var sourceValueExpression = BuildSourceValueExpression(sourceProcessName, outputType, outputProperty);
                if (sourceValueExpression == null) return null;
                // æž„建设置目标值的表达式
                var setTargetExpression = BuildSetTargetExpression(targetParameter, inputType, inputProperty, sourceValueExpression);
                if (setTargetExpression == null) return null;
                // ç¼–译为委托
                var lambda = Expression.Lambda<Action<IProcess>>(setTargetExpression, targetParameter);
                return lambda.Compile();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"创建映射动作失败: {ex.Message}");
                return null;
            }
        }
        private Expression BuildSourceValueExpression(string sourceProcessName, string outputType, string outputProperty)
        {
            // èŽ·å–æºæµç¨‹å®žä¾‹ï¼š_processContext[sourceProcessName]
            var contextField = Expression.Constant(_processContext);
            var processNameConstant = Expression.Constant(sourceProcessName);
            var getItemMethod = typeof(ConcurrentDictionary<string, IProcess>).GetMethod("get_Item");
            var getProcessExpr = Expression.Call(contextField, getItemMethod, processNameConstant);
            // è½¬æ¢ä¸º IProcess
            var convertExpr = Expression.Convert(getProcessExpr, typeof(IProcess));
            // æ·»åŠ  null æ£€æŸ¥
            var nullCheck = Expression.NotEqual(convertExpr, Expression.Constant(null, typeof(IProcess)));
            // æ ¹æ®è¾“出类型和属性构建获取值的表达式
            Expression valueExpression = outputType switch
            {
                "Inputs" => BuildInputsValueExpression(convertExpr, outputProperty),
                "Outputs" => BuildOutputsValueExpression(convertExpr, outputProperty),
                _ => Expression.Constant(null, typeof(object))
            };
            // å¦‚果源流程为 null,返回 null,否则返回值
            return Expression.Condition(nullCheck, valueExpression, Expression.Constant(null, typeof(object)));
        }
        private Expression BuildInputsValueExpression(Expression processExpr, string propertyName)
        {
            if (propertyName == "Image")
            {
                // é¦–先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "InputImage");
            }
            else
            {
                return BuildInputsConcurrentDictionaryExpression(processExpr, propertyName);
            }
        }
        private Expression BuildOutputsValueExpression(Expression processExpr, string propertyName)
        {
            if (propertyName == "Image")
            {
                // é¦–先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "OutputImage");
            }
            else if (propertyName == "Result")
            {
                // é¦–先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "Result");
            }
            else if (propertyName == "Fixture")
            {
                // é€šè¿‡ Params èŽ·å– Fixture
                var paramsExpr = GetMemberExpression(processExpr, "Params");
                return GetMemberExpression(paramsExpr, "Fixture");
            }
            else
            {
                return BuildOutputsConcurrentDictionaryExpression(processExpr, propertyName);
            }
        }
        private Expression BuildInputsConcurrentDictionaryExpression(Expression processExpr, string propertyName)
        {
            // process.Params.Inputs[propertyName]
            var paramsExpr = GetMemberExpression(processExpr, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                throw new InvalidOperationException("Inputs ç±»åž‹æ²¡æœ‰å­—符串索引器");
            var propertyNameConstant = Expression.Constant(propertyName);
            return Expression.Property(inputsExpr, indexer, propertyNameConstant);
        }
        private Expression BuildOutputsConcurrentDictionaryExpression(Expression processExpr, string propertyName)
        {
            // process.Params.Outputs[propertyName]
            var paramsExpr = GetMemberExpression(processExpr, "Params");
            var outputsExpr = GetMemberExpression(paramsExpr, "Outputs");
            var indexer = outputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                throw new InvalidOperationException("Outputs ç±»åž‹æ²¡æœ‰å­—符串索引器");
            var propertyNameConstant = Expression.Constant(propertyName);
            return Expression.Property(outputsExpr, indexer, propertyNameConstant);
        }
        /// <summary>
        /// é€šç”¨çš„æˆå‘˜è®¿é—®æ–¹æ³•:首先尝试字段,然后尝试属性
        /// </summary>
        private Expression GetMemberExpression(Expression instance, string memberName)
        {
            var type = instance.Type;
            // é¦–先尝试字段
            var field = type.GetField(memberName, BindingFlags.Public | BindingFlags.Instance);
            if (field != null)
            {
                return Expression.Field(instance, field);
            }
            // ç„¶åŽå°è¯•属性
            var property = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.Instance);
            if (property != null)
            {
                return Expression.Property(instance, property);
            }
            throw new InvalidOperationException($"在类型 {type.Name} ä¸­æ‰¾ä¸åˆ°å­—段或属性: {memberName}");
        }
        private Expression BuildSetTargetExpression(ParameterExpression targetParameter, string inputType, string inputProperty, Expression sourceValueExpression)
        {
            return inputProperty switch
            {
                "Image" => BuildSetImageExpression(targetParameter, sourceValueExpression),
                "Fixture" => BuildSetFixtureExpression(targetParameter, sourceValueExpression),
                "Result" => BuildSetResultExpression(targetParameter, inputProperty, sourceValueExpression),
                _ => BuildSetInputExpression(targetParameter, inputProperty, sourceValueExpression)
            };
        }
        private Expression BuildSetImageExpression(ParameterExpression target, Expression sourceValue)
        {
            // target.InputImage = sourceValue
            var inputImageExpr = GetMemberExpression(target, "InputImage");
            return Expression.Assign(inputImageExpr, Expression.Convert(sourceValue, inputImageExpr.Type));
        }
        private Expression BuildSetFixtureExpression(ParameterExpression target, Expression sourceValue)
        {
            //// target.Params.Fixture = sourceValue ?? new Fixture()
            //var paramsExpr = GetMemberExpression(target, "Params");
            //var fixtureExpr = GetMemberExpression(paramsExpr, "Fixture");
            //// å¦‚果源值为null,创建新的Fixture
            //var newFixtureExpr = Expression.New(typeof(Fixture));
            //var coalesceExpr = Expression.Coalesce(
            //    Expression.Convert(sourceValue, typeof(Fixture)),
            //    newFixtureExpr
            //);
            //return Expression.Assign(fixtureExpr, coalesceExpr);
            // å¦‚果源值为null,就设置为null,不创建新对象
            var paramsExpr = GetMemberExpression(target, "Params");
            var fixtureExpr = GetMemberExpression(paramsExpr, "Fixture");
            var convertedSourceValue = Expression.Convert(sourceValue, typeof(Fixture));
            return Expression.Assign(fixtureExpr, convertedSourceValue);
        }
        private Expression BuildSetResultExpression(ParameterExpression target, string propertyName, Expression sourceValue)
        {
            // target.Params.Inputs[propertyName] = sourceValue
            var paramsExpr = GetMemberExpression(target, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                return Expression.Empty();
            var propertyNameConstant = Expression.Constant(propertyName);
            var targetIndexExpr = Expression.Property(inputsExpr, indexer, propertyNameConstant);
            return Expression.Assign(targetIndexExpr, Expression.Convert(sourceValue, targetIndexExpr.Type));
        }
        private Expression BuildSetInputExpression(ParameterExpression target, string propertyName, Expression sourceValue)
        {
            // æ£€æŸ¥å­—典是否包含该键,如果包含则赋值
            var paramsExpr = GetMemberExpression(target, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
            var containsMethod = inputsExpr.Type.GetMethod("Contains", new[] { typeof(string) });
            if (containsMethod == null)
                return Expression.Empty();
            var propertyNameConstant = Expression.Constant(propertyName);
            var containsCall = Expression.Call(inputsExpr, containsMethod, propertyNameConstant);
            // å¦‚果包含键,则赋值
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                return Expression.Empty();
            var targetIndexExpr = Expression.Property(inputsExpr, indexer, propertyNameConstant);
            var assignExpr = Expression.Assign(
                targetIndexExpr,
                Expression.Convert(sourceValue, targetIndexExpr.Type)
            );
            // æ¡ä»¶è¡¨è¾¾å¼ï¼šif (inputs.Contains(propertyName)) { inputs[propertyName] = sourceValue; }
            return Expression.IfThen(containsCall, assignExpr);
        }
        public void UpdateInputs(IProcess process)
        {
            if (_compiledMappings.TryGetValue(process.strProcessName, out var actions))
            {
                foreach (var action in actions)
                {
                    try
                    {
                        action(process);
                    }
                    catch (Exception ex)
                    {
                        // å¤„理运行时异常
                        Debug.WriteLine($"执行映射动作失败: {ex.Message}");
                    }
                }
            }
        }
        public void Dispose()
        {
            foreach (var list in _compiledMappings.Values)
            {
                list.Clear();
            }
            _compiledMappings.Clear();
        }
        public void ClearMappings()
        {
            _compiledMappings.Clear();
        }
        public void RemoveProcessMappings(string processName)
        {
            _compiledMappings.TryRemove(processName, out _);
        }
    }
    // è¾…助扩展方法,用于调试
    public static class ExpressionTreeDebugExtensions
    {
        public static void DebugMemberAccess(this ExpressionTreeMappingEngine engine, IProcess testProcess)
        {
            var processType = typeof(IProcess);
            Debug.WriteLine("=== IProcess æˆå‘˜è°ƒè¯•信息 ===");
            Debug.WriteLine("字段:");
            foreach (var field in processType.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                Debug.WriteLine($"  {field.Name} : {field.FieldType.Name}");
            }
            Debug.WriteLine("属性:");
            foreach (var prop in processType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                Debug.WriteLine($"  {prop.Name} : {prop.PropertyType.Name}");
            }
            // æµ‹è¯•具体成员访问
            try
            {
                var processExpr = Expression.Parameter(typeof(IProcess), "p");
                var outputImageExpr = Expression.Field(processExpr, "OutputImage");
                var lambda = Expression.Lambda<Func<IProcess, object>>(outputImageExpr, processExpr).Compile();
                var result = lambda(testProcess);
                Debug.WriteLine($"OutputImage å­—段访问成功: {result ?? "null"}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"OutputImage å­—段访问失败: {ex.Message}");
            }
        }
    }
}
LB_SmartVision/ProcessRun/ProcessContext.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,698 @@
using HalconDotNet;
using LB_SmartVision.Forms.Pages.SettingPage;
using LB_SmartVision.Tool;
using LB_VisionFlowNode;
using LB_VisionProcesses;
using LB_VisionProcesses.Alogrithms;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Processes.ScriptTool;
using OpenCvSharp;
using System.Collections.Concurrent;
namespace LB_SmartVision.ProcessRun
{
    public class ProcessContext : IFlowContext
    {
        /// <summary>
        /// é€šè®¯é›†åˆ(Key:通讯名,Value:通讯句柄)
        /// </summary>
        public ObservableConcurrentDictionary<string, BaseCommunicator> dicCommunicators { get; set; }
        /// <summary>
        /// ç›¸æœºé›†åˆ(Key:相机SN,Value:相机句柄)
        /// </summary>
        public ObservableConcurrentDictionary<string, BaseCamera> dicCameras { get; set; }
        public ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping { get; set; }
        public ConcurrentDictionary<string, List<string>> dicOutputsMapping { get; set; }
        /// <summary>
        /// è¿è¡Œæµç¨‹
        /// </summary>
        public ConcurrentDictionary<string, IProcess> dicContext = new ConcurrentDictionary<string, IProcess>();
        /// <summary>
        /// è¿è¡Œæ ‡è®°
        /// </summary>
        public bool bRuning = false;
        /// <summary>
        /// è¿è¡Œå®Œæˆ
        /// </summary>
        public bool bCompleted = true;
        /// <summary>
        /// è¿è¡Œç»“æžœ
        /// </summary>
        public bool Result = false;
        /// <summary>
        /// è¿è¡Œæ¶ˆæ¯
        /// </summary>
        public string Msg = string.Empty;
        /// <summary>
        /// è¿è¡Œæ—¶é—´
        /// </summary>
        public double RunTime = 0;
        /// <summary>
        /// å¼€å§‹æ—¶é—´
        /// </summary>
        public DateTime StartTime = DateTime.Now;
        private HTuple ho_ImageWidth = new HTuple();
        private HTuple ho_ImageHeight = new HTuple();
        /// <summary>
        /// ç”¨äºŽç»˜åˆ¶ç»“果图的窗口控件
        /// </summary>
        private HWindowControl hWindowControl = new HWindowControl();
        public ProcessContext(ObservableConcurrentDictionary<string, BaseCamera> dicCameras, ObservableConcurrentDictionary<string, BaseCommunicator> dicCommunicators
            , ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping, ConcurrentDictionary<string, List<string>> dicOutputsMapping)
        {
            this.dicCameras = dicCameras;
            this.dicCommunicators = dicCommunicators;
            this.dicInputsMapping = dicInputsMapping;
            this.dicOutputsMapping = dicOutputsMapping;
            hWindowControl.Size = new System.Drawing.Size(1920, 1080);
            TAlgorithm.set_display_font(hWindowControl.HalconWindow, 1080 / 20, "mono", "true", "false");
            HOperatorSet.SetLineWidth(hWindowControl.HalconWindow, 5);
            InitializeMethods();
            InitializeDelegates();
            mappingEngine = new ExpressionTreeMappingEngine(dicContext);
        }
        // åˆå§‹åŒ–
        ExpressionTreeMappingEngine mappingEngine = null;
        /// <summary>
        /// ç¼–译映射
        /// </summary>
        public void CompileMappings()
        {
            mappingEngine = new ExpressionTreeMappingEngine(dicContext);
            mappingEngine.CompileMappings(dicInputsMapping);
        }
        /// <summary>
        /// æ›´æ–°è¾“入(高性能执行)
        /// </summary>
        /// <param name="process"></param>
        public void UpdateInputs(IProcess process)
        {
            mappingEngine.UpdateInputs(process);
        }
        //void UpdateInputs(IProcess process)
        //{
        //    string ProcessName = process.strProcessName;
        //    List<Tuple<string, string>> listTuples = dicInputsMapping[ProcessName];
        //    foreach (var tuple in listTuples)
        //    {
        //        if (string.IsNullOrEmpty(tuple.Item2) || tuple.Item2.Trim() == "")
        //            continue;
        //        string[] arrInputs = tuple.Item1.Split(".");
        //        if (arrInputs.Length < 3)
        //            continue;
        //        string InputProcessName = arrInputs[0];
        //        string strInput = arrInputs[1];
        //        string InputValueName = arrInputs[2];
        //        string[] arrOutputs = tuple.Item2.Split(".");
        //        if (arrOutputs.Length < 2)
        //            continue;
        //        string IndexProcessName = arrOutputs[0];
        //        string IndexIsInputOrOutput = arrOutputs[1];
        //        string IndexValueName = arrOutputs.Length == 3 ? arrOutputs[2] : "";
        //        //这里的o是你所指向的输出流程
        //        object o = dicContext[IndexProcessName];
        //        if (o == null)
        //            continue;
        //        else if (o is IProcess)
        //        {
        //            IProcess i = (IProcess)o;
        //            if (i.strProcessName != IndexProcessName)
        //                continue;
        //            if (InputValueName == "Image")
        //            {
        //                switch (IndexIsInputOrOutput)
        //                {
        //                    case "Inputs":
        //                        //实际上不允许索引的值是输入
        //                        if (IndexValueName == "Image")
        //                            process.InputImage = i.InputImage;
        //                        else
        //                            process.InputImage = i.Params.Inputs[IndexValueName];
        //                        break;
        //                    case "Outputs":
        //                        if (IndexValueName == "Image")
        //                            process.InputImage = i.OutputImage;
        //                        else
        //                            process.InputImage = i.Params.Outputs[IndexValueName];
        //                        break;
        //                    default:
        //                        process.InputImage = null;
        //                        break;
        //                }
        //                if (IndexValueName == "")
        //                    process.InputImage = null;
        //            }
        //            else if (InputValueName == "Fixture")
        //            {
        //                //赋值参数
        //                switch (IndexIsInputOrOutput)
        //                {
        //                    case "Inputs":
        //                        //实际上不允许索引的值是输入
        //                        process.Params.Fixture = i.Params.Fixture;
        //                        break;
        //                    case "Outputs":
        //                        process.Params.Fixture = i.Params.Fixture;
        //                        break;
        //                    default:
        //                        //process.Params.Fixture = new Fixture();
        //                        break;
        //                }
        //                if (IndexValueName == "")
        //                    process.Params.Fixture = new Fixture();
        //            }
        //            else if (IndexValueName == "Result")
        //            {
        //                //赋值参数
        //                switch (IndexIsInputOrOutput)
        //                {
        //                    case "Inputs":
        //                        //实际上不允许索引的值是输入
        //                        process.Params.Inputs[InputValueName] = i.Result;
        //                        break;
        //                    case "Outputs":
        //                        process.Params.Inputs[InputValueName] = i.Result;
        //                        break;
        //                    default:
        //                        process.Params.Inputs[InputValueName] = null;
        //                        break;
        //                }
        //            }
        //            else if (process.Params.Inputs.Contains(InputValueName))
        //            {
        //                //赋值参数
        //                switch (IndexIsInputOrOutput)
        //                {
        //                    case "Inputs":
        //                        //实际上不允许索引的值是输入
        //                        process.Params.Inputs[InputValueName] = i.Params.Inputs[IndexValueName];
        //                        break;
        //                    case "Outputs":
        //                        process.Params.Inputs[InputValueName] = i.Params.Outputs[IndexValueName];
        //                        break;
        //                    default:
        //                        process.Params.Inputs[InputValueName] = null;
        //                        break;
        //                }
        //            }
        //        }
        //    }
        //}
        public bool GetValue(string map, out object obj)
        {
            obj = null;
            if (string.IsNullOrEmpty(map))
                return false;
            try
            {
                string[] arrMap = map.Split(".");
                if (arrMap.Length <= 1)
                    return false;
                string IndexProcessName = arrMap[0];
                string IndexIsInputOrOutput = arrMap[1];
                string IndexValueName = arrMap.Length == 3 ? arrMap[2] : "";
                //这里的o是你所指向的输出流程
                object o = dicContext[IndexProcessName];
                if (o != null && o is IProcess i)
                {
                    if (i.strProcessName != IndexProcessName)
                        return false;
                    if (IndexValueName == "Result")
                    {
                        switch (IndexIsInputOrOutput)
                        {
                            case "Inputs":
                                //实际上不允许索引的值是输入
                                obj = i.Result;
                                break;
                            case "Outputs":
                                obj = i.Result;
                                break;
                            default:
                                return false;
                        }
                    }
                    else
                    {
                        //赋值参数
                        switch (IndexIsInputOrOutput)
                        {
                            case "Inputs":
                                obj = i.Params.Inputs[IndexValueName];
                                break;
                            case "Outputs":
                                obj = i.Params.Outputs[IndexValueName];
                                break;
                            default:
                                return false;
                        }
                    }
                    return true;
                }
                else
                    return false;
            }
            catch { obj = null; return false; }
        }
        public bool GetStringOutput(string map, out string str)
        {
            bool res = GetValue(map, out object obj);
            str = ProcessParams.ConvertToString(obj);
            return res;
        }
        public bool GetImage(Layout layout, out HObject InputImage, out HObject RecordImage)
        {
            InputImage = null; RecordImage = null;
            try
            {
                if (layout == null)
                    return false;
                string ProcessName = layout.ProcessName;
                string InputImageMap = layout.InputImage;
                string RecordImageMap1 = layout.RecordImage1;
                string RecordImageMap2 = layout.RecordImage2;
                string RecordImageMap3 = layout.RecordImage3;
                string[] arrOutputs = new string[] { };
                string IndexProcessName = string.Empty;
                string IndexIsInputOrOutput = string.Empty;
                string IndexValueName = string.Empty;
                #region èŽ·å–è¾“å…¥å›¾ç‰‡
                arrOutputs = InputImageMap.Split(".");
                if (arrOutputs.Length > 2)
                {
                    IndexProcessName = arrOutputs[0];
                    IndexIsInputOrOutput = arrOutputs[1];
                    IndexValueName = arrOutputs[2];
                    object o_InputImage = ((IProcess)dicContext[IndexProcessName]).OutputImage;
                    if (o_InputImage is HObject ho_image && ho_image.IsInitialized())
                        InputImage = ho_image;
                    else if (o_InputImage is Bitmap)
                    {
                        //将Mat转换为HObject
                        TAlgorithm.Bitmap2HObject((Bitmap)o_InputImage, out HObject ho_RecordImage);
                        InputImage = ho_RecordImage;
                    }
                    else if (o_InputImage is Mat)
                    {
                        //将Mat转换为HObject
                        TAlgorithm.Mat2HObject((Mat)o_InputImage, out HObject ho_RecordImage);
                        InputImage = ho_RecordImage;
                    }
                    if (InputImage != null && InputImage.IsInitialized())
                    {
                        HOperatorSet.GetImageSize(InputImage, out ho_ImageWidth, out ho_ImageHeight);
                        //图片尺寸变化才更新窗口尺寸[提高速度]
                        if ((ho_ImageWidth.Length > 0 && ho_ImageWidth.TupleInt() != hWindowControl.Size.Width)
                            || (ho_ImageHeight.Length > 0 && ho_ImageHeight.TupleInt() != hWindowControl.Size.Height))
                        {
                            hWindowControl.Invoke(new Action(() =>
                            {
                                hWindowControl.Size = new System.Drawing.Size(ho_ImageWidth, ho_ImageHeight);
                                TAlgorithm.set_display_font(hWindowControl.HalconWindow, ho_ImageWidth.I / 20, "mono", "true", "false");
                            }));
                        }
                    }
                    TAlgorithm.DispImage(InputImage, hWindowControl.HalconWindow);
                }
                #endregion
                #region ç»˜åˆ¶ç»“果图
                arrOutputs = RecordImageMap1.Split(".");
                if (arrOutputs.Length > 2)
                {
                    IndexProcessName = arrOutputs[0];
                    IndexIsInputOrOutput = arrOutputs[1];
                    IndexValueName = arrOutputs[2];
                    if (dicContext.ContainsKey(IndexProcessName))
                    {
                        ObjectRecord objectRecord1 = ((IProcess)dicContext[IndexProcessName]).Record;
                        if (objectRecord1 != null)
                        {
                            objectRecord1.Display(hWindowControl.HalconWindow);
                            objectRecord1.Dispose();
                        }
                    }
                }
                arrOutputs = RecordImageMap2.Split(".");
                if (arrOutputs.Length > 2)
                {
                    IndexProcessName = arrOutputs[0];
                    IndexIsInputOrOutput = arrOutputs[1];
                    IndexValueName = arrOutputs[2];
                    if (dicContext.ContainsKey(IndexProcessName))
                    {
                        ObjectRecord objectRecord2 = ((IProcess)dicContext[IndexProcessName]).Record;
                        if (objectRecord2 != null)
                        {
                            objectRecord2.Display(hWindowControl.HalconWindow);
                            objectRecord2.Dispose();
                        }
                    }
                }
                arrOutputs = RecordImageMap3.Split(".");
                if (arrOutputs.Length > 2)
                {
                    IndexProcessName = arrOutputs[0];
                    IndexIsInputOrOutput = arrOutputs[1];
                    IndexValueName = arrOutputs[2];
                    if (dicContext.ContainsKey(IndexProcessName))
                    {
                        ObjectRecord objectRecord3 = ((IProcess)dicContext[IndexProcessName]).Record;
                        if (objectRecord3 != null)
                        {
                            objectRecord3.Display(hWindowControl.HalconWindow);
                            objectRecord3.Dispose();
                        }
                    }
                }
                if (Result)
                {
                    Msg = "运行成功";
                    HOperatorSet.SetColor(hWindowControl.HalconWindow, "green");
                }
                else
                    HOperatorSet.SetColor(hWindowControl.HalconWindow, "red");
                TAlgorithm.DispMsg(Msg, hWindowControl.HalconWindow, Result ? "green" : "red", 0, 0);
                HOperatorSet.DumpWindowImage(out RecordImage, hWindowControl.HalconWindow);
                #endregion
                return true;
            }
            catch { return false; }
        }
        public bool GetCsv(CsvSetting csv, out List<string> DataTitle, out Dictionary<string, object> ResultData)
        {
            // æ•°æ®æ ‡é¢˜
            DataTitle = (new string[] { "名称", "时间", "耗时", "结果", "原因" }).ToList();
            ResultData = new Dictionary<string, object>();
            try
            {
                ResultData.Add("名称", csv.ProcessName);
                ResultData.Add("时间", DateTime.Now.ToString("HH:mm:ss.ff"));
                ResultData.Add("耗时", $"{RunTime.ToString("F2")}");
                ResultData.Add("结果", Result);
                ResultData.Add("原因", Msg);
                for (int i = 0; i < csv.Others.Count; i++)
                {
                    string title = $"数据{i}";
                    string map = csv.Others[i];
                    GetValue(map, out object obj);
                    if (obj == null)
                        continue;
                    Type type = obj.GetType();
                    switch (type)
                    {
                        case Type t when t == typeof(double):
                            ResultData.Add(title, ((double)obj).ToString("F4"));
                            DataTitle.Add(title);
                            break;
                        default:
                            ResultData.Add(title, ProcessParams.ConvertToString(obj));
                            DataTitle.Add(title);
                            break;
                    }
                }
                return true;
            }
            catch { return false; }
        }
        /// <summary>
        /// éžåˆ†æ”¯èŠ‚ç‚¹çš„ç»Ÿä¸€è°ƒç”¨æ–¹å¼
        /// </summary>
        private void RunNodeAsync(FlowNode node)
        {
            // èµ°é»˜è®¤åˆ†æ”¯
            node.BranchIndex = "0";
            string ProcessName = node.Text;
            try
            {
                if (dicContext.TryGetValue(ProcessName, out IProcess obj)
                    && obj is IProcess process)
                {
                    process.InputImage = null;
                    UpdateInputs(process);
                    // ä¸åŒèŠ‚ç‚¹è·³è¿‡çš„æ–¹å¼ä¸åŒ
                    if (node.Break)
                    {
                        switch (node.Description)
                        {
                            case "T306通讯":
                                node.BranchIndex = "0";
                                node.Result = true;
                                process.Result = false;
                                process.Msg = "T306通讯未启用";
                                return;
                            default:
                                node.BranchIndex = "0";
                                node.Result = true;
                                process.Result = true;
                                process.Msg = string.Empty;
                                return;
                        }
                    }
                    if (!process.Run())
                    {
                        node.Result = false;
                        Result &= false;
                        if (!string.IsNullOrEmpty(process.Msg)
                            && !Msg.Contains($"[{process.strProcessName}]{process.Msg}"))
                            Msg += $"[{process.strProcessName}]{process.Msg}";
                    }
                    else
                        node.Result = true;
                }
            }
            catch (Exception ex)
            {
                node.Result = false;
                Result &= false;
                Msg += $"[{ProcessName}]运行发生意外,{ex.Message}";
            }
        }
        [Node("开始", "控制", "Logic", "开始")]
        public override void å¼€å§‹(FlowNode node)
        {
            StartTime = DateTime.Now;
            RunTime = 0;
            Result = true;
            bRuning = true;
            bCompleted = false;
            Msg = string.Empty;
            HOperatorSet.ClearWindow(hWindowControl.HalconWindow);
            HOperatorSet.SetColor(hWindowControl.HalconWindow, "green");
        }
        [Node("结束", "控制", "Logic", "结束")]
        public override void ç»“束(FlowNode node)
        {
            bRuning = false;
            bCompleted = true;
            if (Result)
                Msg = "运行成功";
            RunTime = (DateTime.Now - StartTime).TotalMilliseconds;
        }
        [Node("分支", "控制", "Logic", "分支")]
        public override void åˆ†æ”¯(FlowNode node)
        {
            string ProcessName = node.Text;
            node.BranchIndex = "-1";
            node.Result = true;
            try
            {
                if (dicContext.TryGetValue(ProcessName, out IProcess obj) && obj is ScriptTool script)
                {
                    UpdateInputs(script);
                    if (node.Break)
                    {
                        node.BranchIndex = "0";
                        node.Result = true;
                        script.Result = true;
                        script.Msg = string.Empty;
                        return;
                    }
                    if (script.Params.Outputs.Count >= 2)
                    {
                        if (!script.Run())
                        {
                            node.Result = false;
                            Result &= false;
                            Msg = $"[{ProcessName}]{script.Msg}";
                        }
                        for (int i = 0; i < script.Params.Outputs.Count; i++)
                        {
                            if (script.Params.Outputs[$"Branch{i}"] != null
                                && Convert.ToBoolean(script.Params.Outputs[$"Branch{i}"]))
                            {
                                node.BranchIndex = i.ToString();
                                return;
                            }
                        }
                        node.Result = false;
                        Result &= false;
                        Msg = $"[{ProcessName}]无满足条件的分支";
                    }
                    else
                    {
                        node.Result = false;
                        Result &= false;
                        Msg = $"[{ProcessName}]分支数量不为2";
                    }
                }
                else
                {
                    node.Result = false;
                    Result &= false;
                }
            }
            catch (Exception ex)
            {
                node.Result = false;
                Result &= false;
                Msg = $"[{ProcessName}]运行发生意外,{ex.Message}";
            }
        }
        [Node("多分支", "控制", "Logic", "多分支")]
        public override void å¤šåˆ†æ”¯(FlowNode node)
        {
            if (node.Break)
            {
                node.BranchIndex = "0";
                node.Result = true;
                return;
            }
            string ProcessName = node.Text;
            node.BranchIndex = "-1";
            node.Result = true;
            try
            {
                if (dicContext.TryGetValue(ProcessName, out IProcess obj) && obj is ScriptTool script)
                {
                    UpdateInputs(script);
                    if (node.Break)
                    {
                        node.BranchIndex = "0";
                        node.Result = true;
                        script.Result = true;
                        script.Msg = string.Empty;
                        return;
                    }
                    if (script.Params.Outputs.Count >= 1)
                    {
                        if (!script.Run())
                        {
                            node.Result = false;
                            Result &= false;
                            Msg = $"[{ProcessName}]{script.Msg}";
                        }
                        for (int i = 0; i < script.Params.Outputs.Count; i++)
                        {
                            if (script.Params.Outputs[$"Branch{i}"] != null
                                && Convert.ToBoolean(script.Params.Outputs[$"Branch{i}"]))
                            {
                                node.BranchIndex = i.ToString();
                                return;
                            }
                        }
                        node.Result = false;
                        Result &= false;
                        Msg = $"[{ProcessName}]无满足条件的分支";
                    }
                    else
                    {
                        node.Result = false;
                        Result &= false;
                        Msg = $"[{ProcessName}]多分支数量小于1";
                    }
                }
                else
                {
                    node.Result = false;
                    Result &= false;
                }
            }
            catch (Exception ex)
            {
                node.Result = false;
                Result &= false;
                Msg = $"[{ProcessName}]运行发生意外,{ex.Message}";
            }
        }
    }
}
LB_SmartVision/ProcessRun/ProcessRunBll.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,958 @@
using HalconDotNet;
using LB_SmartVision.Forms.Pages.SettingPage;
using LB_SmartVision.Tool;
using LB_VisionFlowNode;
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Processes.ScriptTool;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using OpenCvSharp;
using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using System.Text;
namespace LB_SmartVision.ProcessRun
{
    public class ProcessRunBll
    {
        private ProcessContext ProcessContext = null;
        public static string Node2ToolClassName(string NodeName)
        {
            foreach (var item in IProcess.dicProcesses)
            {
                if (NodeName.StartsWith(item.Key))
                    return item.Value.ToString();
            }
            return string.Empty;
        }
        /// <summary>
        /// æµç¨‹åç§°
        /// </summary>
        public string Name = string.Empty;
        /// <summary>
        /// è¿è¡Œæ ‡è®°
        /// </summary>
        public bool bPruning
        {
            set
            {
                if (ProcessContext == null)
                    return;
                ProcessContext.bRuning = value;
            }
            get
            {
                if (ProcessContext == null)
                    return false;
                return ProcessContext.bRuning;
            }
        }
        /// <summary>
        /// è¿è¡Œå®Œæˆ
        /// </summary>
        public bool bCompleted
        {
            set
            {
                if (ProcessContext == null)
                    return;
                ProcessContext.bCompleted = value;
            }
            get
            {
                if (ProcessContext == null)
                    return false;
                return ProcessContext.bCompleted;
            }
        }
        /// <summary>
        /// è¿è¡Œç»“æžœ
        /// </summary>
        public bool Result
        {
            set
            {
                if (ProcessContext == null)
                    return;
                ProcessContext.Result = value;
            }
            get
            {
                if (ProcessContext == null)
                    return false;
                return ProcessContext.Result;
            }
        }
        /// <summary>
        /// è¿è¡Œæ¶ˆæ¯
        /// </summary>
        public string Msg
        {
            set
            {
                if (ProcessContext == null)
                    return;
                ProcessContext.Msg = value;
            }
            get
            {
                if (ProcessContext == null)
                    return "运行失败";
                return ProcessContext.Msg;
            }
        }
        /// <summary>
        /// è¿è¡Œæ—¶é—´(ms)
        /// </summary>
        public double RunTime = 0;
        public bool GetImage(Forms.Pages.SettingPage.Layout layout, out HObject InputImage, out HObject RecordImage)
        {
            return ProcessContext.GetImage(layout, out InputImage, out RecordImage);
        }
        public bool GetImage(out HObject InputImage, out HObject RecordImage)
        {
            InputImage = null;
            RecordImage = null;
            foreach (var layout in GlobalVar.dicLayout)
            {
                if (layout.Value.ProcessName == Name)
                    return ProcessContext.GetImage(layout.Value, out InputImage, out RecordImage);
            }
            return false;
        }
        public bool GetCsv(CsvSetting csv, out List<string> DataTitle, out Dictionary<string, object> ResultData)
        {
            return ProcessContext.GetCsv(csv, out DataTitle, out ResultData);
        }
        public bool GetOutput(string map, out object obj)
        {
            return ProcessContext.GetValue(map, out obj);
        }
        public bool GetStringOutput(string map, out string str)
        {
            bool res = GetOutput(map, out object obj);
            str = ProcessParams.ConvertToString(obj);
            return res;
        }
        public bool GetBooleanOutput(string map, out bool ret)
        {
            try
            {
                if (!GetOutput(map, out object obj))
                {
                    ret = false;
                    return ret;
                }
                ret = Convert.ToBoolean(obj);
                return true;
            }
            catch
            {
                ret = false;
                return ret;
            }
        }
        public ConcurrentDictionary<string, IProcess> GetSteps()
        {
            if (ProcessContext.dicContext == null)
                return new ConcurrentDictionary<string, IProcess>();
            return ProcessContext.dicContext;
        }
        /// <summary>
        /// è¿è¡Œæµç¨‹
        /// </summary>
        public FlowPanel nodesControl = null;
        /// <summary>
        /// é€šè®¯é›†åˆ(Key:通讯名,Value:通讯句柄)
        /// </summary>
        public ObservableConcurrentDictionary<string, BaseCommunicator> dicCommunicators { get; set; }
        /// <summary>
        /// ç›¸æœºé›†åˆ(Key:相机SN,Value:相机句柄)
        /// </summary>
        public ObservableConcurrentDictionary<string, BaseCamera> dicCameras { get; set; }
        public Action<string, LogInfoType> LogInfo;
        public string allProcessPath
        {
            get
            {
                return GlobalVar.allProcessPath + Name + "\\default.nds";
            }
        }
        public string allProcessInputsSettingPath
        {
            get
            {
                return GlobalVar.allProcessPath + Name + "\\A_ProcessInputs.json";
            }
        }
        public string allProcessOutputsSettingPath
        {
            get
            {
                return GlobalVar.allProcessPath + Name + "\\A_ProcessOutputs.json";
            }
        }
        public ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping = new ConcurrentDictionary<string, List<Tuple<string, string>>>();
        public ConcurrentDictionary<string, List<string>> dicOutputsMapping = new ConcurrentDictionary<string, List<string>>();
        public ProcessRunBll() { }
        public ProcessRunBll(string Name
            , ObservableConcurrentDictionary<string, BaseCamera> dicCameras
            , ObservableConcurrentDictionary<string, BaseCommunicator> dicCommunicators)
        {
            this.Name = Name;
            this.dicCameras = dicCameras;
            this.dicCommunicators = dicCommunicators;
        }
        public bool Load(out string msg)
        {
            try
            {
                if (!LoadInputs())
                {
                    msg = "加载输入失败";
                    return false;
                }
                if (!LoadOutputs())
                {
                    msg = "加载输出失败";
                    return false;
                }
                if (!allProcessPath.Contains(".nds"))
                {
                    msg = "文件路径不完整";
                    return false;
                }
                ProcessContext = new ProcessContext(dicCameras, dicCommunicators, dicInputsMapping, dicOutputsMapping);
                nodesControl = new FlowPanel(ProcessContext);
                if (!File.Exists(allProcessPath))
                {
                    Save(out msg);
                    msg = "文件不存在,创建默认布局";
                }
                else
                {
                    byte[] bytes = File.ReadAllBytes(allProcessPath);
                    try
                    {
                        nodesControl.Load(allProcessPath);
                    }
                    catch
                    {
                        msg = $"文件损坏,长度为{bytes.Length}";
                        return false;
                    }
                }
                foreach (var node in nodesControl.GetAllNodes().Values)
                {
                    string ProcessName = node.Text;
                    string ClassDescription = node.Description;
                    string ClassName = Node2ToolClassName(ClassDescription);
                    string ProcessPath = GlobalVar.allProcessPath + Name + "\\" + ProcessName + ".json";
                    if (!AddStep(Name, ProcessName, ClassName, ProcessPath))
                        LogInfo?.Invoke(string.Format("流程[{0}]添加\"{1}\"失败", Name, ProcessName), LogInfoType.ERROR);
                }
                msg = "加载布局成功";
                CompileMappings();
                return true;
            }
            catch { msg = "加载布局失败"; return false; }
        }
        public bool Save(out string msg)
        {
            try
            {
                if (!SaveInputs())
                {
                    msg = "保存输入失败";
                    return false;
                }
                if (!SaveOutputs())
                {
                    msg = "保存输出失败";
                    return false;
                }
                var dicSteps = GetSteps();
                if (nodesControl.Save(allProcessPath))
                {
                    msg = "保存布局成功";
                    return true;
                }
                else
                {
                    msg = "保存布局失败";
                    return false;
                }
            }
            catch { msg = "保存布局失败"; return false; }
        }
        public bool LoadInputs()
        {
            try
            {
                if (!allProcessInputsSettingPath.Contains(".json"))
                {
                    Debug.WriteLine("文件路径不完整");
                    return false;
                }
                if (!File.Exists(allProcessInputsSettingPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allProcessInputsSettingPath);
                    SaveInputs();
                    return true;
                }
                // å¦‚果文件存在,则先移除隐藏属性
                if (File.Exists(allProcessInputsSettingPath))
                    File.SetAttributes(allProcessInputsSettingPath, File.GetAttributes(allProcessInputsSettingPath) & ~FileAttributes.Hidden);
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allProcessInputsSettingPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                dicInputsMapping = JsonConvert.DeserializeObject<ConcurrentDictionary<string, List<Tuple<string, string>>>>(strJson);
                if (File.Exists(allProcessInputsSettingPath))
                {
                    // èŽ·å–æ–‡ä»¶ä¿¡æ¯
                    FileInfo fileInfo = new FileInfo(allProcessInputsSettingPath);
                    // è®¾ç½®æ–‡ä»¶ä¸ºéšè—
                    fileInfo.Attributes |= FileAttributes.Hidden;
                }
                if (dicInputsMapping == null)
                    return false;
                SaveInputs();
                return true;
            }
            catch { return false; }
        }
        public bool SaveInputs()
        {
            string strJson = string.Empty;
            var settings = new JsonSerializerSettings
            {
                Formatting = Newtonsoft.Json.Formatting.Indented,
                // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                }
            };
            strJson = JsonConvert.SerializeObject(dicInputsMapping, settings);
            //判断文件夹是否存在,防呆输入为文件名称
            if (!Directory.Exists(Path.GetDirectoryName(allProcessInputsSettingPath)))
            {
                try
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(allProcessInputsSettingPath));
                }
                catch (Exception)
                { }
            }
            // å¦‚果文件存在,则先移除隐藏属性
            if (File.Exists(allProcessInputsSettingPath))
                File.SetAttributes(allProcessInputsSettingPath, File.GetAttributes(allProcessInputsSettingPath) & ~FileAttributes.Hidden);
            File.WriteAllText(allProcessInputsSettingPath, strJson, Encoding.UTF8);
            if (File.Exists(allProcessInputsSettingPath))
            {
                // èŽ·å–æ–‡ä»¶ä¿¡æ¯
                FileInfo fileInfo = new FileInfo(allProcessInputsSettingPath);
                // è®¾ç½®æ–‡ä»¶ä¸ºéšè—
                fileInfo.Attributes |= FileAttributes.Hidden;
            }
            CompileMappings();
            return true;
        }
        public bool LoadOutputs()
        {
            try
            {
                if (!allProcessOutputsSettingPath.Contains(".json"))
                {
                    Debug.WriteLine("文件路径不完整");
                    return false;
                }
                if (!File.Exists(allProcessOutputsSettingPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allProcessOutputsSettingPath);
                    SaveInputs();
                    return true;
                }
                // å¦‚果文件存在,则先移除隐藏属性
                if (File.Exists(allProcessOutputsSettingPath))
                    File.SetAttributes(allProcessOutputsSettingPath, File.GetAttributes(allProcessOutputsSettingPath) & ~FileAttributes.Hidden);
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allProcessOutputsSettingPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                dicOutputsMapping = JsonConvert.DeserializeObject<ConcurrentDictionary<string, List<string>>>(strJson);
                if (File.Exists(allProcessOutputsSettingPath))
                {
                    // èŽ·å–æ–‡ä»¶ä¿¡æ¯
                    FileInfo fileInfo = new FileInfo(allProcessOutputsSettingPath);
                    // è®¾ç½®æ–‡ä»¶ä¸ºéšè—
                    fileInfo.Attributes |= FileAttributes.Hidden;
                }
                if (dicOutputsMapping == null)
                    return false;
                SaveOutputs();
                return true;
            }
            catch { return false; }
        }
        public bool SaveOutputs()
        {
            string strJson = string.Empty;
            var settings = new JsonSerializerSettings
            {
                Formatting = Newtonsoft.Json.Formatting.Indented,
                // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new CamelCaseNamingStrategy()
                }
            };
            strJson = JsonConvert.SerializeObject(dicOutputsMapping, settings);
            //判断文件夹是否存在,防呆输入为文件名称
            if (!Directory.Exists(Path.GetDirectoryName(allProcessOutputsSettingPath)))
            {
                try
                {
                    Directory.CreateDirectory(Path.GetDirectoryName(allProcessOutputsSettingPath));
                }
                catch (Exception)
                { }
            }
            // å¦‚果文件存在,则先移除隐藏属性
            if (File.Exists(allProcessOutputsSettingPath))
                File.SetAttributes(allProcessOutputsSettingPath, File.GetAttributes(allProcessOutputsSettingPath) & ~FileAttributes.Hidden);
            File.WriteAllText(allProcessOutputsSettingPath, strJson, Encoding.UTF8);
            if (File.Exists(allProcessOutputsSettingPath))
            {
                // èŽ·å–æ–‡ä»¶ä¿¡æ¯
                FileInfo fileInfo = new FileInfo(allProcessOutputsSettingPath);
                // è®¾ç½®æ–‡ä»¶ä¸ºéšè—
                fileInfo.Attributes |= FileAttributes.Hidden;
            }
            CompileMappings();
            return true;
        }
        /// <summary>
        /// æ·»åŠ å•ä¸ªæ­¥éª¤åˆ°æµç¨‹é˜Ÿåˆ—ä¸­
        /// </summary>
        /// <param name="Camera"></param>
        /// <param name="ProcessName"></param>
        /// <param name="ClassName"></param>
        /// <param name="ProcessPath"></param>
        /// <param name="listProcesses"></param>
        public bool AddStep(string Name, string ProcessName, string ClassName, string ProcessPath)
        {
            try
            {
                if (nodesControl == null || !(nodesControl.Context is ProcessContext))
                    return false;
                if (((ProcessContext)nodesControl.Context).dicContext.ContainsKey(ProcessName))
                {
                    LogInfo?.Invoke(string.Format("流程[{0}]已存在步骤[{1}]添加失败", Name, ProcessName), LogInfoType.WARN);
                    return false;
                }
                //利用反射进行创建
                if (ClassName.Contains("Cameras"))
                {
                    Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]);
                    if (type == null)
                    {
                        Debug.WriteLine("Class not found.");
                        return false;
                    }
                    CameraConfig CameraConfig = Activator.CreateInstance(type, new object[] { dicCameras.Items }) as CameraConfig;
                    if (CameraConfig == null)
                    {
                        Debug.WriteLine("Cameras not found.");
                        return false;
                    }
                    CameraConfig.Load(ProcessPath);
                    CameraConfig.strProcessName = ProcessName;
                    AddInputsAndOutputs(CameraConfig.strProcessName, CameraConfig);
                }
                else if (ClassName.Contains("Communicators"))
                {
                    Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]);
                    if (type == null)
                    {
                        Debug.WriteLine("Class not found.");
                        return false;
                    }
                    CommunicatorConfig CommunicatorConfig = Activator.CreateInstance(type, new object[] { dicCommunicators.Items }) as CommunicatorConfig;
                    if (CommunicatorConfig == null)
                    {
                        Debug.WriteLine("Communicators not found.");
                        return false;
                    }
                    CommunicatorConfig.Load(ProcessPath);
                    CommunicatorConfig.strProcessName = ProcessName;
                    AddInputsAndOutputs(CommunicatorConfig.strProcessName, CommunicatorConfig);
                }
                else if (!string.IsNullOrEmpty(ClassName))
                {
                    //利用反射进行创建
                    Type type = IProcess.GetExecutingAssembly().GetType(ClassName.Split(',')[0]);
                    if (type == null)
                    {
                        Debug.WriteLine("Class not found.");
                        return false;
                    }
                    IProcess process = Activator.CreateInstance(type) as IProcess;
                    if (process == null)
                    {
                        Debug.WriteLine("IProcess not found.");
                        return false;
                    }
                    process.Load(ProcessPath);
                    process.strProcessName = ProcessName;
                    //if (process is VisionProTool && Tool.ContainsChinese(ProcessName))
                    //    MessageBox.Show($"VisionPro工具不支持命名为中文:{ProcessName}", "异常");
                    if (process is ScriptTool script)
                    {
                        if (script.Params.Outputs.Count <= 0)
                            script.Params.Outputs.Add("Branch0", true);
                        if (script.Params.Outputs.Count <= 1)
                            script.Params.Outputs.Add("Branch1", false);
                    }
                    AddInputsAndOutputs(process.strProcessName, process);
                }
                LogInfo?.Invoke(string.Format("流程[{0}]添加步骤[{1}]", Name, ProcessName), LogInfoType.INFO);
                return true;
            }
            catch (Exception ex) { Debug.WriteLine("AddProcessToList失败,原因是" + ex.Message.ToString()); return false; }
        }
        public void AddInputsAndOutputs(string name, IProcess obj)
        {
            try
            {
                if (obj == null)
                    return;
                if (nodesControl.Context == null || !(nodesControl.Context is ProcessContext))
                    return;
                ((ProcessContext)nodesControl.Context).dicContext.TryAdd(name, obj);
                if (obj is IProcess process)
                {
                    if (!dicInputsMapping.ContainsKey(name))
                    {
                        dicInputsMapping.TryAdd(name, new List<Tuple<string, string>>());
                        dicInputsMapping[name].Add(new Tuple<string, string>(name + ".Inputs.Image", ""));
                        //dicInputsMapping[name].Add(new Tuple<string, string>(name + ".Inputs.Fixture", ""));
                        foreach (var item in process.Params.Inputs)
                            dicInputsMapping[name].Add(new Tuple<string, string>(name + ".Inputs." + item.Name, ""));
                    }
                    if (!dicOutputsMapping.ContainsKey(name))
                    {
                        dicOutputsMapping.TryAdd(name, new List<string>());
                        dicOutputsMapping[name].Add(name + ".Outputs.Image");
                        dicOutputsMapping[name].Add(name + ".Outputs.Record");
                        dicOutputsMapping[name].Add(name + ".Outputs.Result");
                        //dicOutputsMapping[name].Add(name + ".Outputs.Fixture");
                        foreach (var item in process.Params.Outputs)
                            dicOutputsMapping[name].Add(name + ".Outputs." + item.Name);
                    }
                    CompileMappings();
                }
            }
            catch { }
        }
        public void CompileMappings()
        {
            try
            {
                if (ProcessContext != null)
                {
                    ProcessContext.CompileMappings();
                }
            }
            catch { }
        }
        public void UpdataInputsAndOutputs(string name, IProcess obj)
        {
            if (obj == null)
                return;
            if (obj is IProcess process)
            {
                if (dicInputsMapping.ContainsKey(name))
                {
                    foreach (var item in process.Params.Inputs)
                    {
                        if (dicInputsMapping[name].Where(x => x.Item1 == name + ".Inputs." + item.Name).Count() == 0)
                            dicInputsMapping[name].Add(new Tuple<string, string>(name + ".Inputs." + item.Name, ""));
                    }
                }
                if (dicOutputsMapping.ContainsKey(name))
                {
                    foreach (var item in process.Params.Outputs)
                    {
                        if (dicOutputsMapping[name].Where(x => x == name + ".Outputs." + item.Name).Count() == 0)
                            dicOutputsMapping[name].Add(name + ".Outputs." + item.Name);
                    }
                }
                CompileMappings();
            }
        }
        public bool Remove(string ProcessName)
        {
            try
            {
                if (ProcessContext == null)
                    return false;
                ConcurrentDictionary<string, IProcess> dicSteps = GetSteps();
                if (!dicSteps.ContainsKey(ProcessName))
                    return false;
                Object obj = dicSteps[ProcessName];
                if (obj == null)
                    return false;
                string strProcessName = ((IProcess)obj).strProcessName;
                if (!string.IsNullOrEmpty(strProcessName))
                {
                    dicInputsMapping.TryRemove(strProcessName, out List<Tuple<string, string>> tempInputs);
                    dicOutputsMapping.TryRemove(strProcessName, out List<string> tempOutputs);
                    if (dicSteps.TryRemove(strProcessName, out IProcess tempObj))
                        LogInfo?.Invoke(string.Format("流程[{0}]移除步骤[{1}]", Name, strProcessName), LogInfoType.INFO);
                    else
                        LogInfo?.Invoke(string.Format("流程[{0}]移除步骤[{1}]失败", Name, strProcessName), LogInfoType.WARN);
                    SaveInputs();
                    SaveOutputs();
                    CompileMappings();
                    return true;
                }
                return false;
            }
            catch { return false; }
        }
        void Rename(IProcess obj, string newName)
        {
            if (obj == null)
                return;
            ((IProcess)obj).strProcessName = newName;
            LogInfo?.Invoke(string.Format("流程[{0}]重命名步骤[{1}]", Name, newName), LogInfoType.INFO);
        }
        /// <summary>
        /// é‡å‘½åæ­¥éª¤(!不是重命名流程!)
        /// </summary>
        /// <param name="oldName"></param>
        /// <param name="newName"></param>
        public void Rename(string oldName, string newName)
        {
            if (ProcessContext == null)
                return;
            var dicSteps = GetSteps();
            if (!dicSteps.ContainsKey(oldName))
                return;
            dicSteps.TryRemove(oldName, out IProcess process);
            dicSteps.TryAdd(newName, process);
            Rename(process, newName);
            ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping = new ConcurrentDictionary<string, List<Tuple<string, string>>>();
            foreach (var InputsMapping in this.dicInputsMapping)
            {
                if (InputsMapping.Key == oldName)
                {
                    List<Tuple<string, string>> tempTuples = new List<Tuple<string, string>>();
                    foreach (var tuple in InputsMapping.Value)
                    {
                        string[] arrInputs = tuple.Item1.Split(".");
                        string InputProcessName = arrInputs[0];
                        string strInput = arrInputs[1];
                        string InputValueName = arrInputs[2];
                        string Input = "";
                        if (InputProcessName == oldName)
                            Input = newName + "." + strInput + "." + InputValueName;
                        else
                            Input = tuple.Item1;
                        tempTuples.Add(Tuple.Create(Input, tuple.Item2));
                    }
                    dicInputsMapping.TryAdd(newName, tempTuples);
                }
                else
                {
                    List<Tuple<string, string>> tempTuples = new List<Tuple<string, string>>();
                    foreach (var tuple in InputsMapping.Value)
                    {
                        string[] arrInputs = tuple.Item1.Split(".");
                        if (arrInputs.Length < 3)
                        {
                            tempTuples.Add(tuple);
                            continue;
                        }
                        string InputProcessName = arrInputs[0];
                        string strInput = arrInputs[1];
                        string InputValueName = arrInputs[2];
                        string[] arrOutputs = tuple.Item2.Split(".");
                        if (arrOutputs.Length < 3)
                        {
                            tempTuples.Add(tuple);
                            continue;
                        }
                        string IndexProcessName = arrOutputs[0];
                        string IndexIsInputOrOutput = arrOutputs[1];
                        string IndexValueName = arrOutputs[2];
                        if (IndexProcessName == oldName)
                        {
                            tempTuples.Add(new Tuple<string, string>(tuple.Item1
                                , string.Format("{0}.{1}.{2}", newName, IndexIsInputOrOutput, IndexValueName)));
                        }
                        else
                            tempTuples.Add(tuple);
                    }
                    dicInputsMapping.TryAdd(InputsMapping.Key, tempTuples);
                }
            }
            this.dicInputsMapping = ProcessContext.dicInputsMapping = dicInputsMapping;
            ConcurrentDictionary<string, List<string>> dicOutputsMapping = new ConcurrentDictionary<string, List<string>>();
            foreach (var OutputsMapping in this.dicOutputsMapping)
            {
                if (OutputsMapping.Key == oldName)
                {
                    List<string> listOutputs = new List<string>();
                    foreach (string Output in OutputsMapping.Value)
                    {
                        string[] arrOutputs = Output.Split(".");
                        if (arrOutputs.Length < 3)
                        {
                            listOutputs.Add(Output);
                            continue;
                        }
                        string IndexProcessName = arrOutputs[0];
                        string IndexIsInputOrOutput = arrOutputs[1];
                        string IndexValueName = arrOutputs[2];
                        if (IndexProcessName == oldName)
                        {
                            listOutputs.Add(string.Format("{0}.{1}.{2}", newName, IndexIsInputOrOutput, IndexValueName));
                        }
                        else
                            listOutputs.Add(Output);
                    }
                    dicOutputsMapping.TryAdd(newName, listOutputs);
                }
                else
                    dicOutputsMapping.TryAdd(OutputsMapping.Key, OutputsMapping.Value);
            }
            this.dicOutputsMapping = ProcessContext.dicOutputsMapping = dicOutputsMapping;
            SaveInputs();
            SaveOutputs();
            CompileMappings();
        }
        double total_OK;
        double total_NG;
        public double total
        {
            get { return total_OK + total_NG; }
        }
        public double Rate_OK
        {
            get
            {
                if (total == 0)
                    return 100;
                return (total_OK / total) * 100;
            }
        }
        public void ClearTotal()
        {
            total_OK = 0;
            total_NG = 0;
        }
        /// <summary>
        /// è°ƒç”¨Run必须是在Inovk中否则会报线程错误,该类的Run调用需要封装在UI内
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public bool Run()
        {
            bPruning = true;
            bCompleted = false;
            DateTime StartTime = DateTime.Now;
            try
            {
                Result = true;
                if (!nodesControl.Run(out string msg) && !string.IsNullOrEmpty(msg))
                {
                    Msg += $"【{msg}】";
                    Result &= false;
                }
            }
            catch (Exception ex)
            {
                Result = false;
                Msg = string.Format("运行发送了意外{0}", ex.Message.Trim());
            }
            RunTime = (DateTime.Now - StartTime).TotalMilliseconds;
            bPruning = false;
            bCompleted = true;
            if (Result)
            {
                total_OK++;
                Msg = "运行成功";
            }
            else
                total_NG++;
            if (IProcess.dicGlobalVars.ContainsKey($"{Name}.Result"))
                IProcess.dicGlobalVars[$"{Name}.Result"] = Result;
            else
                IProcess.dicGlobalVars.TryAdd($"{Name}.Result", Result);
            if (IProcess.dicGlobalVars.ContainsKey($"{Name}.Msg"))
                IProcess.dicGlobalVars[$"{Name}.Msg"] = Msg;
            else
                IProcess.dicGlobalVars.TryAdd($"{Name}.Msg", Msg);
            // æ‰‹åŠ¨è§¦å‘åžƒåœ¾å›žæ”¶
            GC.Collect();
            return Result;
        }
        public void LogoInfo(string info, LogInfoType logInfoType)
        {
            LogInfo?.Invoke(info, logInfoType);
        }
    }
}
LB_SmartVision/Program.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,17 @@
namespace LB_SmartVision
{
    internal static class Program
    {
        /// <summary>
        ///  The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            // To customize application configuration such as set high DPI settings or default font,
            // see https://aka.ms/applicationconfiguration.
            ApplicationConfiguration.Initialize();
            Application.Run(new VisionForm());
        }
    }
}
LB_SmartVision/Properties/Resources.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     æ­¤ä»£ç ç”±å·¥å…·ç”Ÿæˆã€‚
//     è¿è¡Œæ—¶ç‰ˆæœ¬:4.0.30319.42000
//
//     å¯¹æ­¤æ–‡ä»¶çš„æ›´æ”¹å¯èƒ½ä¼šå¯¼è‡´ä¸æ­£ç¡®çš„行为,并且如果
//     é‡æ–°ç”Ÿæˆä»£ç ï¼Œè¿™äº›æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚
// </auto-generated>
//------------------------------------------------------------------------------
namespace LB_SmartVision.Properties {
    using System;
    /// <summary>
    ///   ä¸€ä¸ªå¼ºç±»åž‹çš„资源类,用于查找本地化的字符串等。
    /// </summary>
    // æ­¤ç±»æ˜¯ç”± StronglyTypedResourceBuilder
    // ç±»é€šè¿‡ç±»ä¼¼äºŽ ResGen æˆ– Visual Studio çš„工具自动生成的。
    // è‹¥è¦æ·»åŠ æˆ–ç§»é™¤æˆå‘˜ï¼Œè¯·ç¼–è¾‘ .ResX æ–‡ä»¶ï¼Œç„¶åŽé‡æ–°è¿è¡Œ ResGen
    // (以 /str ä½œä¸ºå‘½ä»¤é€‰é¡¹),或重新生成 VS é¡¹ç›®ã€‚
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resources {
        private static global::System.Resources.ResourceManager resourceMan;
        private static global::System.Globalization.CultureInfo resourceCulture;
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resources() {
        }
        /// <summary>
        ///   è¿”回此类使用的缓存的 ResourceManager å®žä¾‹ã€‚
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LB_SmartVision.Properties.Resources", typeof(Resources).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        /// <summary>
        ///   é‡å†™å½“前线程的 CurrentUICulture å±žæ€§ï¼Œå¯¹
        ///   ä½¿ç”¨æ­¤å¼ºç±»åž‹èµ„源类的所有资源查找执行重写。
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
    }
}
LB_SmartVision/Properties/Resources.resx
¶Ô±ÈÐÂÎļþ
@@ -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>
LB_SmartVision/README.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1 @@
# LB_SmartVision
LB_SmartVision/Tool/ObservableConcurrentDictionary.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,186 @@
using System.Collections;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace LB_SmartVision.Tool
{
    public class ObservableConcurrentDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        public readonly ConcurrentDictionary<TKey, TValue> Items = new();
        public ICollection<TKey> Keys => ((IDictionary<TKey, TValue>)Items).Keys;
        public ICollection<TValue> Values => ((IDictionary<TKey, TValue>)Items).Values;
        public int Count => ((ICollection<KeyValuePair<TKey, TValue>>)Items).Count;
        public bool IsReadOnly => ((ICollection<KeyValuePair<TKey, TValue>>)Items).IsReadOnly;
        public event EventHandler<DictionaryChangedEventArgs<TKey, TValue>> DictionaryChanged;
        public TValue this[TKey key]
        {
            get
            {
                return Items.TryGetValue(key, out TValue Value) ? Value : default;
            }
            set
            {
                //bool exists = Items.TryGetValue(key, out TValue oldValue);
                if (Items.ContainsKey(key))
                    Items[key] = value;
                //if (exists)
                //    OnDictionaryChanged(DictionaryChangeType.Updated, key, key, value, oldValue);
            }
        }
        public bool TryAdd(TKey key, TValue value)
        {
            if (Items.ContainsKey(key))
            {
                Items[key] = value;
                return true;
            }
            if (Items.TryAdd(key, value))
            {
                OnDictionaryChanged(DictionaryChangeType.Added, key, key, value, value);
                return true;
            }
            return false;
        }
        public bool TryRemove(TKey key, out TValue value)
        {
            if (Items.TryRemove(key, out value))
            {
                OnDictionaryChanged(DictionaryChangeType.Removed, key, key, default, value);
                return true;
            }
            return false;
        }
        public bool TryRename(TKey oldKey, TKey newKey)
        {
            if (Items.TryRemove(oldKey, out TValue value))
            {
                Items.TryAdd(newKey, value);
                OnDictionaryChanged(DictionaryChangeType.Renamed, newKey, oldKey, value, value);
                return true;
            }
            return false;
        }
        protected virtual void OnDictionaryChanged(DictionaryChangeType changeType, TKey newKey, TKey oldKey, TValue newValue, TValue oldValue)
        {
            var handlers = DictionaryChanged;
            if (handlers != null)
            {
                foreach (EventHandler<DictionaryChangedEventArgs<TKey, TValue>> handler in handlers.GetInvocationList())
                {
                    try
                    {
                        handler(this, new DictionaryChangedEventArgs<TKey, TValue>(changeType, newKey, oldKey, newValue, oldValue));
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine($"事件处理异常: {ex.Message}");
                    }
                }
            }
            //DictionaryChanged?.Invoke(this,
            //    new DictionaryChangedEventArgs<TKey, TValue>(changeType, newKey, oldKey, newValue, oldValue));
        }
        public void Add(TKey key, TValue value)
        {
            ((IDictionary<TKey, TValue>)Items).Add(key, value);
        }
        // åœ¨ç±»ä¸­æ·»åŠ ç±»åž‹æ£€æŸ¥
        private static readonly bool IsStringKey = typeof(TKey) == typeof(string);
        public bool ContainsKey(TKey key)
        {
            if (!IsStringKey || key == null)
                return ((IDictionary<TKey, TValue>)Items).ContainsKey(key);
            var searchKey = key as string;
            return ((IDictionary<TKey, TValue>)Items).Keys.Any(k =>
                string.Equals(k as string, searchKey, StringComparison.OrdinalIgnoreCase));
        }
        public bool Remove(TKey key)
        {
            return ((IDictionary<TKey, TValue>)Items).Remove(key);
        }
        public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
        {
            return ((IDictionary<TKey, TValue>)Items).TryGetValue(key, out value);
        }
        public void Add(KeyValuePair<TKey, TValue> item)
        {
            ((ICollection<KeyValuePair<TKey, TValue>>)Items).Add(item);
        }
        public void Clear()
        {
            foreach (var kvp in Items)
                OnDictionaryChanged(DictionaryChangeType.Removed, kvp.Key, kvp.Key, default, kvp.Value);
            ((ICollection<KeyValuePair<TKey, TValue>>)Items).Clear();
        }
        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            return ((ICollection<KeyValuePair<TKey, TValue>>)Items).Contains(item);
        }
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            ((ICollection<KeyValuePair<TKey, TValue>>)Items).CopyTo(array, arrayIndex);
        }
        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            return ((ICollection<KeyValuePair<TKey, TValue>>)Items).Remove(item);
        }
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            return ((IEnumerable<KeyValuePair<TKey, TValue>>)Items).GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)Items).GetEnumerator();
        }
        // å®žçް其他IDictionary成员...
    }
    public enum DictionaryChangeType { Added, Removed, Renamed, Updated }
    public class DictionaryChangedEventArgs<TKey, TValue> : EventArgs
    {
        public DictionaryChangeType ChangeType { get; }
        public TKey NewKey { get; }
        public TKey OldKey { get; }
        public TValue NewValue { get; }
        public TValue OldValue { get; }
        public DictionaryChangedEventArgs(DictionaryChangeType changeType, TKey newKey, TKey oldKey, TValue newValue, TValue oldValue)
        {
            ChangeType = changeType;
            NewKey = newKey;
            OldKey = oldKey;
            NewValue = newValue;
            OldValue = oldValue;
        }
    }
}
LB_SmartVision/Tool/OperateIniHelper.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Collections.Specialized.BitVector32;
namespace LB_SmartVision.Tool
{
    public class OperateIniHelper
    {
        private string _iniFilePath = "Config";
        /// <summary>
        /// IniFilePath需要包含.ini,在引用前需要设置FileName
        /// </summary>
        public string IniFilePath
        {
            get
            {
                return System.IO.Path.Combine(Application.StartupPath, _iniFilePath, _iniFileName);
            }
            set
            {
                _iniFilePath = value;
            }
        }
        private string _iniFileName = "Default.ini";
        public static string Suffix = ".ini";
        private bool bClosedIni = false;
        public string IniFileName
        {
            get
            {
                return _iniFileName;
            }
            set
            {
                int index = value.LastIndexOf('.');
                // å¦‚果没有找到分隔符,则返回原始字符串
                if (index == -1)
                    _iniFileName = value + Suffix;
                else
                    _iniFileName = value.Substring(0, index) + Suffix;
            }
        }
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern int WritePrivateProfileString(string section, string key, string value, string filePath);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private static extern int GetPrivateProfileString(string section, string key, string defaultValue, StringBuilder returnValue, int size, string filePath);
        public OperateIniHelper() { }
        public OperateIniHelper(string iniFileName = "MyAlgorithm_1", string iniFilePath = "MyAlgorithm")
        {
            IniFileName = iniFileName;
            IniFilePath = iniFilePath;
            GetValidFilePath(IniFilePath);
        }
        public void SetValue(string section, string key, object value, string path = "")
        {
            // é€‰æ‹©åˆé€‚的编码
            Encoding encoding = Encoding.UTF8;
            if (path != "" && value != null)
            {
                WritePrivateProfileString(section.Trim(), key.Trim(), value.ToString(), path);
                int index = path.LastIndexOf('.');
                if (index != -1)
                {
                    string EncryptPath = path.Substring(0, index) + "_closed" + Suffix;
                    Tool.EncryptFile(path, EncryptPath);
                }
            }
            else if (value != null)
            {
                WritePrivateProfileString(section.Trim(), key.Trim(), value.ToString(), IniFilePath);
                int index = IniFilePath.LastIndexOf('.');
                if (index != -1)
                {
                    string EncryptPath = IniFilePath.Substring(0, index) + "_closed" + Suffix;
                    Tool.EncryptFile(IniFilePath, EncryptPath);
                }
            }
        }
        /// <summary>
        /// èŽ·å–Ini文件值
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public string GetValue(string section, string key, string path = "")
        {
            StringBuilder returnValue = new StringBuilder(255);
            if (path != "" && path != null && GetValidFilePath(path).Item1)
                GetPrivateProfileString(section.Trim(), key.Trim(), string.Empty, returnValue, returnValue.Capacity, path);
            else if (GetValidFilePath(IniFilePath).Item1)
                GetPrivateProfileString(section.Trim(), key.Trim(), string.Empty, returnValue, returnValue.Capacity, IniFilePath);
            //不存在值时写入默认值0
            if (string.IsNullOrEmpty(returnValue.ToString().Trim()))
            {
                string strDefalut = "0";
                if (path != "" && path != null)
                    SetValue(section.Trim(), key.Trim(), strDefalut, path);
                else
                    SetValue(section.Trim(), key.Trim(), strDefalut);
                return strDefalut;
            }
            return returnValue.ToString();
        }
        static (bool, string) GetValidFilePath(string path)
        {
            try
            {
                if (path == "" || path == null)
                    return (false, null);
                // æ£€æŸ¥è·¯å¾„是否包含非法字符
                string fullPath = Path.GetFullPath(path);
                bool result = !string.IsNullOrWhiteSpace(fullPath) && path.Equals(fullPath, StringComparison.OrdinalIgnoreCase);
                // ä¸å­˜åœ¨éžæ³•字符则判断是否需要创建
                if (result)
                {
                    string parentPath = Path.GetDirectoryName(path);
                    // åˆ¤æ–­æ–‡ä»¶å¤¹æ˜¯å¦å­˜åœ¨
                    if (!Directory.Exists(parentPath) && parentPath != null)
                    {
                        try
                        {
                            Directory.CreateDirectory(parentPath);
                            // æ–‡ä»¶ä¸å­˜åœ¨åˆ™å†™å…¥é»˜è®¤å€¼
                        }
                        catch { return (false, null); }
                    }
                }
                return (result, path);
            }
            catch { return (false, null); }
        }
    }
}
LB_SmartVision/Tool/Tool.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1134 @@
using HalconDotNet;
using Microsoft.Win32;
using System.Collections.Concurrent;
using System.Configuration;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace LB_SmartVision.Tool
{
    public sealed class Tool : IDisposable
    {
        // é™æ€æž„造函数启动消费者任务
        static Tool()
        {
            // å¯åŠ¨æ¶ˆè´¹è€…ä»»åŠ¡
            _logConsumerTask = Task.Factory.StartNew(
                () => ProcessLogQueue(_logCts.Token),
                _logCts.Token,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default);
            // FIFO è¡Œä¸ºï¼Œè¶…出容量时阻塞
            _RealImageQueue = new BlockingCollection<ImageSaveTask>(capacity);
            _RealImageCts = new CancellationTokenSource();
            StartRealImageConsumer();
        }
        public void Dispose()
        {
            try
            {
                // åœæ­¢æŽ¥å—新日志
                _logQueue.CompleteAdding();
                // å–消正在进行的操作
                _logCts.Cancel();
                // ç­‰å¾…完成
                if (!_logConsumerTask.Wait(TimeSpan.FromSeconds(5)))
                    Debug.WriteLine("日志线程关闭超时");
                _RealImageCts.Cancel();
                _RealImageQueue.CompleteAdding();
                while (_RealImageQueue.TryTake(out var task))
                {
                    if (task.Image is Bitmap bitmap)
                        bitmap.Dispose();
                    else if (task.Image is HObject hobject)
                        hobject.Dispose();
                }
                _RealImageCts.Dispose();
                _RealImageQueue.Dispose();
                _RealImageConsumerTask?.Dispose();
            }
            catch { }
            finally
            {
                _logCts.Dispose();
                _logQueue.Dispose();
            }
        }
        #region æ—¥å¿—功能
        public static string _logFilePath = Path.Combine(GlobalVar.strPathLog, $"{GlobalVar.strStartTime}.log");
        public static string _logFilePathBackup = Path.Combine(GlobalVar.strPathLog, $"{GlobalVar.strStartTime}(副本).log");
        private static readonly BlockingCollection<string> _logQueue = new BlockingCollection<string>(1024);
        private static readonly CancellationTokenSource _logCts = new CancellationTokenSource();
        private static Task _logConsumerTask;
        private static readonly object _fileLock = new object();
        // æ·»åŠ æ—¥å¿—åˆ°é˜Ÿåˆ—
        public static bool AddLog(string message)
        {
            if (!_logQueue.IsAddingCompleted)
            {
                try
                {
                    _logQueue.Add(message, _logCts.Token);
                    return true;
                }
                catch (InvalidOperationException)
                {
                    // é˜Ÿåˆ—已关闭
                    return false;
                }
            }
            return false;
        }
        // æ¶ˆè´¹è€…任务处理队列
        private static void ProcessLogQueue(CancellationToken ct)
        {
            try
            {
                foreach (var logEntry in _logQueue.GetConsumingEnumerable(ct))
                {
                    lock (_fileLock)
                    {
                        try
                        {
                            File.AppendAllText(_logFilePath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {logEntry}{Environment.NewLine}");
                        }
                        catch
                        {
                            try
                            {
                                // æ—¥å¿—写入失败二次尝试
                                File.AppendAllText(_logFilePath, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {logEntry}{Environment.NewLine}");
                            }
                            catch
                            {
                                try
                                {
                                    // æ—¥å¿—写入失败处理(可添加到备用队列或控制台输出)
                                    File.AppendAllText(_logFilePathBackup, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {logEntry}{Environment.NewLine}");
                                }
                                catch (Exception ex)
                                {
                                    Debug.WriteLine($"日志写入失败: {ex.Message}");
                                }
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // æ­£å¸¸å–消
            }
        }
        // å°è¯•写入文件的辅助方法
        private static bool TryWriteToFile(string path, byte[] data)
        {
            try
            {
                using (var stream = new FileStream(
                    path,
                    FileMode.Append,
                    FileAccess.Write,
                    FileShare.ReadWrite,
                    bufferSize: 4096,
                    useAsync: true))
                {
                    stream.Write(data, 0, data.Length);
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }
        #endregion
        #region å­˜åŽŸå›¾åŠŸèƒ½
        /// <summary>
        /// è¶…出容量时阻塞
        /// </summary>
        private static readonly BlockingCollection<ImageSaveTask> _RealImageQueue;
        private static readonly CancellationTokenSource _RealImageCts;
        private static Task _RealImageConsumerTask;
        private static int _restartCount;
        private const int MaxRestarts = 5;
        private static int capacity = 10; // é˜Ÿåˆ—容量
        // èŽ·å–æŒ‡å®šå›¾åƒæ ¼å¼çš„ç¼–ç å™¨ä¿¡æ¯
        private static ImageCodecInfo GetEncoder(ImageFormat format)
        {
            // èŽ·å–æ‰€æœ‰å·²å®‰è£…çš„å›¾åƒç¼–ç å™¨
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
            // æŸ¥æ‰¾åŒ¹é…æŒ‡å®šæ ¼å¼çš„编码器
            return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid);
        }
        public static long _imageQuality = 100L;
        static ImageCodecInfo jpegEncoder = null;
        static EncoderParameters encoderParams = null;
        static char[] invalidChars = Path.GetInvalidFileNameChars();
        // å›¾ç‰‡ä¿å­˜ä»»åŠ¡ç»“æž„
        public struct ImageSaveTask
        {
            public object Image { get; set; }
            public string FullPath { get; set; }
            public string ImageType { get; set; }
            public long Quality { get; set; }
            public ImageSaveTask(object image, string fullPath, string imageType = "jpg", long quality = 50L)
            {
                Image = image;
                FullPath = fullPath;
                ImageType = imageType.ToLower();
                Quality = quality;
            }
        }
        private static void StartRealImageConsumer()
        {
            _RealImageConsumerTask = Task.Run(async () =>
            {
                try
                {
                    await RealImageProcessQueue();
                }
                catch when (_RealImageCts.IsCancellationRequested)
                {
                    // æ­£å¸¸å…³é—­
                }
                catch (Exception ex)
                {
                    if (++_restartCount <= MaxRestarts)
                    {
                        StartRealImageConsumer(); // è‡ªåŠ¨é‡å¯
                    }
                    AddLog($"保存图片StartRealImageConsumer出现异常:{ex.Message}");
                }
            }, _RealImageCts.Token);
        }
        private static async Task RealImageProcessQueue()
        {
            foreach (var task in _RealImageQueue.GetConsumingEnumerable(_RealImageCts.Token))
            {
                try
                {
                    await SaveImageAsync(task);
                }
                catch (Exception ex)
                {
                    AddLog($"保存图片RealImageProcessQueue出现异常:{ex.Message}");
                }
                finally
                {
                    if (task.Image != null)
                    {
                        if (task.Image is Bitmap bitmap)
                            bitmap.Dispose();
                        if (task.Image is HObject hobject)
                            hobject.Dispose();
                    }
                }
            }
        }
        public static void AddRealImage(object image, string filePath, string fileName, string imageType = "jpg", long quality = 50L)
        {
            if (_RealImageCts.IsCancellationRequested)
                throw new InvalidOperationException("Processor is shutting down");
            if (IsSave(filePath))
            {
                string fullPath = Path.Combine(filePath, $"{fileName}.{imageType.ToLower()}");
                // FIFO è¡Œä¸ºï¼Œè¶…出容量时阻塞
                //// ç¼“存图片大于容量说明磁盘存储不过来了,取出所有元素直到队列为空
                //if (_RealImageQueue.Count >= capacity + 1)
                //{
                //    AddLog("缓存图片超过10å¼ ,清空已经缓存的旧图片");
                //    while (_RealImageQueue.TryTake(out _)) { }
                //}
                if (image is HObject hObject)
                {
                    _RealImageQueue.Add(new ImageSaveTask
                    {
                        Image = hObject.Clone(),
                        FullPath = fullPath,
                        ImageType = imageType.ToLower(),
                        Quality = quality
                    }, _RealImageCts.Token);
                }
                else if (image is Bitmap bitmap)
                {
                    _RealImageQueue.Add(new ImageSaveTask
                    {
                        Image = bitmap.Clone(),
                        FullPath = fullPath,
                        ImageType = imageType.ToLower(),
                        Quality = quality
                    }, _RealImageCts.Token);
                }
            }
        }
        // ç¨‹åºå¯åŠ¨æ—¶åˆå§‹åŒ–ç¼–ç å™¨ç¼“å­˜
        private static readonly Dictionary<Guid, ImageCodecInfo> _encoderCache =
            ImageCodecInfo.GetImageEncoders()
                .ToDictionary(codec => codec.FormatID);
        // é€šè¿‡ImageFormat获取编码器
        private static ImageCodecInfo GetEncoderByFormat(ImageFormat format)
        {
            _encoderCache.TryGetValue(format.Guid, out var encoder);
            return encoder;
        }
        // é€šè¿‡å­—符串类型获取编码器
        private static ImageCodecInfo GetEncoderByType(string imageType)
        {
            var format = GetImageFormat(imageType);
            return GetEncoderByFormat(format);
        }
        // èŽ·å–ImageFormat的辅助方法
        private static ImageFormat GetImageFormat(string imageType)
        {
            switch (imageType.ToLowerInvariant())
            {
                case "jpg":
                case "jpeg": return ImageFormat.Jpeg;
                case "png": return ImageFormat.Png;
                case "bmp": return ImageFormat.Bmp;
                case "gif": return ImageFormat.Gif;
                case "tif":
                case "tiff": return ImageFormat.Tiff;
                default: throw new NotSupportedException($"不支持的图片格式: {imageType}");
            }
        }
        private static async Task SaveImageAsync(ImageSaveTask task)
        {
            try
            {
                // å‚数校验
                if (task.Image == null) throw new ArgumentNullException(nameof(task.Image));
                if (string.IsNullOrWhiteSpace(task.FullPath))
                    throw new ArgumentException("Invalid file path");
                var dir = Path.GetDirectoryName(task.FullPath);
                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                if (task.Image is HObject hObject && hObject.IsInitialized())
                {
                    try
                    {
                        //Halcon存图需要用斜杠
                        task.FullPath.Replace("\\", "/");
                        HOperatorSet.WriteImage(hObject, task.ImageType, 0, task.FullPath);
                    }
                    catch { AddLog("保存图片时HOperatorSet.WriteImage发生异常"); }
                }
                else if (task.Image is Bitmap bitmap)
                {
                    // èŽ·å–å¯¹åº”æ ¼å¼çš„ç¼–ç å™¨
                    ImageCodecInfo encoder = GetEncoderByType(task.ImageType);
                    // é…ç½®ç¼–码参数
                    var encoderParams = new EncoderParameters(1);
                    encoderParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, task.Quality);
                    // ä½¿ç”¨å†…存流中转避免文件锁冲突
                    using (var memoryStream = new MemoryStream())
                    {
                        // åŒæ­¥ç¼–码转异步操作(线程池优化)
                        await Task.Run(() =>
                        {
                            bitmap.Save(memoryStream, encoder, encoderParams);
                            memoryStream.Position = 0; // é‡ç½®æµä½ç½®
                        }).ConfigureAwait(false);
                        // åŽŸå­æ€§å†™å…¥ï¼ˆä¸´æ—¶æ–‡ä»¶+替换)
                        var tempPath = $"{task.FullPath}.{Guid.NewGuid()}.tmp";
                        // å¼‚步文件写入(带缓冲区优化)
                        using (var fileStream = new FileStream(
                            tempPath,
                            FileMode.Create,
                            FileAccess.Write,
                            FileShare.None,
                            bufferSize: 81920, // 80KB缓冲区
                            useAsync: true))
                        {
                            await memoryStream.CopyToAsync(fileStream)
                                .ConfigureAwait(false);
                        }
                        // åŽŸå­æ›¿æ¢æ–‡ä»¶ï¼ˆè·¨å¹³å°å…¼å®¹ï¼‰
                        File.Move(tempPath, task.FullPath);
                    }
                }
            }
            catch (Exception ex) when (IsRetryableException(ex))
            {
                AddLog($"保存图片IsRetryableException出现异常:{ex.Message}");
            }
            catch (Exception ex)
            {
                AddLog($"保存图片SaveImageAsync出现异常:{ex.Message}");
            }
        }
        // åˆ¤æ–­æ˜¯å¦å¯é‡è¯•的异常
        private static bool IsRetryableException(Exception ex)
        {
            return ex is IOException
                or UnauthorizedAccessException
                or TimeoutException;
        }
        #endregion
        #region ç£ç›˜å›žæ”¶åŠŸèƒ½
        public static double MinSpace = 10;
        /// <summary>
        /// èŽ·å–ç£ç›˜å‰©ä½™ç©ºé—´
        /// </summary>
        /// <param name="strPath"></param>
        /// <returns></returns>
        public static double GetHardDiskFreeSpace(string strPath)
        {
            //磁盘名称
            string strHardDiskName = strPath.Substring(0, 1);
            //获取C盘的剩余空间
            DriveInfo cDrive = new DriveInfo(strHardDiskName);
            // æ£€æŸ¥é©±åŠ¨å™¨æ˜¯å¦æ˜¯æœ‰æ•ˆçš„
            if (cDrive.IsReady)
            {
                // èŽ·å–å‰©ä½™ç©ºé—´
                long freeSpace = cDrive.AvailableFreeSpace;
                // å°†å­—节数转换为GB单位
                return (double)freeSpace / (1024 * 1024 * 1024);
            }
            else
                return 0;
        }
        /// <summary>
        /// åˆ¤æ–­æ˜¯å¦å…è®¸ä¿å­˜
        /// </summary>
        /// <param name="fullPath">保存文件的完整路径</param>
        /// <returns></returns>
        public static bool IsSave(string fullPath)
        {
            // èŽ·å–ä¸Šä¸€çº§ç›®å½•ï¼ˆçˆ¶ç›®å½•ï¼‰
            string parentDirectory = Path.GetDirectoryName(fullPath);
            if (GetHardDiskFreeSpace(parentDirectory) >= MinSpace)
                return true;
            else
            {
                if (DeletOutTimeFiles(parentDirectory))
                {
                    // åˆ é™¤è¶…期文件后再次判断容量能否存储
                    if (GetHardDiskFreeSpace(parentDirectory) >= MinSpace)
                        return true;
                    return false;
                }
                else
                    return false;
            }
        }
        /// <summary>
        ///删除超出时间的文件夹路径
        /// </summary>
        /// <param name="directoryPath"></param>
        /// <returns></returns>
        public static bool DeletOutTimeFiles(string directoryPath, int days = 30)
        {
            try
            {
                // ä¿å­˜æ—¶é—´ä¸è¶…过30天
                DateTime NowTime = DateTime.Now; // å½“前日期作为截止日期
                DirectoryInfo directoryInfo = new DirectoryInfo(directoryPath);
                DirectoryInfo[] directories = directoryInfo.GetDirectories();
                for (int i = 0; i < directories.Length; i++)
                {
                    if (directories[i].CreationTime.AddDays(days) < NowTime)
                    {
                        try
                        {
                            Directory.Delete(directories[i].FullName, recursive: true);
                            Debug.WriteLine($"Deleted {directories[i].FullName}");
                        }
                        catch (Exception ex)
                        {
                            // å¯ä»¥é€‰æ‹©åœ¨è¿™é‡Œè®°å½•日志继续处理下一个文件
                            Debug.WriteLine($"Error deleting {directories[i].FullName}: {ex.Message}");
                        }
                    }
                }
                AddLog($"磁盘空间不足,已删除路径[{directoryPath}]超过{days}天的文件,累计{directories.Length}个!");
                return true;
            }
            catch { return false; }
        }
        #endregion
        public static bool ContainsChinese(string text)
        {
            if (string.IsNullOrEmpty(text))
                return false;
            return Regex.IsMatch(text, @"[\u4e00-\u9fa5]");
        }
        /// <summary>
        /// ä¿å­˜CSV到本地
        /// </summary>
        /// <param name="fileDirectoryAndName"></param>
        /// <param name="obj"></param>
        public static void WriteDataToFile(string fileDirectoryAndName, object[] obj)
        {
            try
            {
                string text = "";
                // å†™å…¥CSV文件
                using (var streamWriter = new StreamWriter(fileDirectoryAndName, true, Encoding.UTF8))
                {
                    for (int i = 0; i < obj.Length; i++)
                    {
                        text += (obj[i].ToString().Replace(",", ","));
                        if (i < obj.Length - 1)
                            text += ",";
                    }
                    streamWriter.Write(text);
                    streamWriter.WriteLine(); // å†™å…¥æ¢è¡Œç¬¦
                }
            }
            catch { }
        }
        /// <summary>
        /// ä¿å­˜æ•°æ®åˆ°æœ¬åœ°
        /// </summary>
        /// <param name="strCCDName"></param>
        /// <param name="timeCode"></param>
        /// <param name="productCode"></param>
        /// <param name="result"></param>
        /// <param name="resultData"></param>
        public static void SaveData(string filePath, List<string> DataTitle, Dictionary<string, object> resultData)
        {
            try
            {
                if (resultData.Count <= 0 || resultData == null)
                    return;
                var dir = Path.GetDirectoryName(filePath);
                if (!Directory.Exists(dir))
                    Directory.CreateDirectory(dir);
                if (!File.Exists(filePath))
                    WriteDataToFile(filePath, DataTitle.ToArray());
                List<string> SaveData = new List<string>();
                foreach (var item in DataTitle)
                {
                    if (resultData.ContainsKey(item))
                    {
                        double dData = 0;
                        if (double.TryParse(resultData[item].ToString(), out dData))
                            SaveData.Add(dData.ToString("F2"));
                        else
                            SaveData.Add((resultData[item]?.ToString()).Replace(",", ",").ToString());
                    }
                    else
                        SaveData.Add("NULL");
                }
                try
                {
                    WriteDataToFile(filePath, SaveData.ToArray());
                }
                catch (Exception ex)
                {
                    //文件被占用保存到副本中
                    try
                    {
                        //再次尝试写入
                        WriteDataToFile(filePath, SaveData.ToArray());
                    }
                    catch
                    {
                        //写入失败写到副本中
                        filePath = AddCopySuffix(filePath, "(副本)");
                        if (!File.Exists(filePath))
                            WriteDataToFile(filePath, DataTitle.ToArray());
                        WriteDataToFile(filePath, SaveData.ToArray());
                    }
                }
            }
            catch (Exception ex)
            {
                AddLog("生产数据保存失败,原因是:" + ex.ToString());
            }
        }
        public static string AddCopySuffix(string filePath, string suffix = "(副本)")
        {
            if (string.IsNullOrEmpty(filePath))
                return filePath;
            string directory = Path.GetDirectoryName(filePath);
            string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath);
            string extension = Path.GetExtension(filePath);
            return Path.Combine(directory, $"{fileNameWithoutExtension}({suffix}){extension}");
        }
        /// <summary>
        /// åŠ å¯†æ–‡ä»¶
        /// </summary>
        /// <param name="inputFilePath"></param>
        /// <param name="outputFilePath"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        public static void EncryptFile(string inputFilePath, string outputFilePath, string key = "", string iv = "")
        {
            using (Aes aes = Aes.Create())
            {
                if (key != "")
                {
                    aes.Key = Convert.FromBase64String(key);
                    aes.IV = Convert.FromBase64String(iv);
                }
                else
                {
                    aes.Key = new byte[32];
                    aes.IV = new byte[16];
                }
                using (FileStream outputFileStream = new FileStream(outputFilePath, FileMode.Create))
                using (ICryptoTransform encryptor = aes.CreateEncryptor())
                using (CryptoStream cryptoStream = new CryptoStream(outputFileStream, encryptor, CryptoStreamMode.Write))
                using (FileStream inputFileStream = new FileStream(inputFilePath, FileMode.Open))
                {
                    inputFileStream.CopyTo(cryptoStream);
                }
            }
        }
        /// <summary>
        /// è§£å¯†æ–‡ä»¶
        /// </summary>
        /// <param name="inputFilePath"></param>
        /// <param name="outputFilePath"></param>
        /// <param name="key"></param>
        /// <param name="iv"></param>
        public static void DecryptFile(string inputFilePath, string outputFilePath, string key = "", string iv = "")
        {
            using (Aes aes = Aes.Create())
            {
                if (key != "")
                {
                    aes.Key = Convert.FromBase64String(key);
                    aes.IV = Convert.FromBase64String(iv);
                }
                else
                {
                    aes.Key = new byte[32];
                    aes.IV = new byte[16];
                }
                using (FileStream inputFileStream = new FileStream(inputFilePath, FileMode.Open))
                using (ICryptoTransform decryptor = aes.CreateDecryptor())
                using (CryptoStream cryptoStream = new CryptoStream(inputFileStream, decryptor, CryptoStreamMode.Read))
                using (FileStream outputFileStream = new FileStream(outputFilePath, FileMode.Create))
                {
                    cryptoStream.CopyTo(outputFileStream);
                }
            }
        }
        #region åŠ å¯†ç‹—
        private const string DOG_AES_SALT = "MYAPP_KEY_SALT";
        private const string DOG_AES_KEY = "MYAPP_AES_KEY";
        private const string DOG_AES_IV = "MYAPP_AES_IV";
        private const string REGISTRY_PATH = @"SOFTWARE\MyApp\SoftDog";
        private static bool SetRegistryValue(RegistryKey baseKey, string valueName, string value)
        {
            try
            {
                using (RegistryKey key = baseKey.CreateSubKey(REGISTRY_PATH, RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                    if (key != null)
                    {
                        key.SetValue(valueName, value, RegistryValueKind.String);
                        return true;
                    }
                }
            }
            catch (SecurityException)
            {
                // æƒé™ä¸è¶³ï¼Œæ­£å¸¸æƒ…况
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"设置注册表值失败: {ex.Message}");
            }
            return false;
        }
        private static string GetRegistryValue(string valueName)
        {
            // å…ˆå°è¯•HKLM
            string value = GetRegistryValue(Registry.LocalMachine, valueName);
            if (!string.IsNullOrEmpty(value))
                return value;
            // å†å°è¯•HKCU
            return GetRegistryValue(Registry.CurrentUser, valueName);
        }
        private static string GetRegistryValue(RegistryKey baseKey, string valueName)
        {
            try
            {
                using (RegistryKey key = baseKey.OpenSubKey(REGISTRY_PATH, false))
                {
                    return key?.GetValue(valueName) as string;
                }
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// èŽ·å–AES加密参数
        /// </summary>
        public static (byte[] Key, byte[] IV) GetAesParameters()
        {
            try
            {
                string keyBase64 = GetRegistryValue(DOG_AES_KEY);
                string ivBase64 = GetRegistryValue(DOG_AES_IV);
                // å¦‚果系统级没有,尝试用户级
                if (!string.IsNullOrEmpty(keyBase64) && !string.IsNullOrEmpty(ivBase64))
                {
                    byte[] key = Convert.FromBase64String(keyBase64);
                    byte[] iv = Convert.FromBase64String(ivBase64);
                    return (key, iv);
                }
                return (null, null);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"获取AES参数失败: {ex.Message}");
                return (null, null);
            }
        }
        /// <summary>
        /// éªŒè¯åŠ å¯†ç‹—
        /// </summary>
        public static bool ValidateAesDog()
        {
            var (key, iv) = GetAppBoundKey("VisionUltra");
            if (key == null || iv == null)
                return false;
            // éªŒè¯å¯†é’¥å’ŒIV的格式和长度
            return key.Length == 32 && iv.Length == 16; // AES-256: 32字节密钥, 16字节IV
        }
        /// <summary>
        /// ç”Ÿæˆä¸Žåº”用绑定的AES加密狗
        /// </summary>
        public static bool GenerateAppBoundDog(string appIdentifier)
        {
            try
            {
                using (Aes aes = Aes.Create())
                {
                    aes.GenerateKey();
                    aes.GenerateIV();
                    // ä½¿ç”¨åº”用标识符作为盐值
                    byte[] salt = Encoding.UTF8.GetBytes(appIdentifier);
                    // åŠ å¯†å¯†é’¥æœ¬èº«ï¼ˆå¯é€‰çš„å®‰å…¨å¢žå¼ºï¼‰
                    byte[] encryptedKey = EncryptKeyWithSalt(aes.Key, salt, aes.IV);
                    // å­˜å‚¨åŠ å¯†åŽçš„å¯†é’¥å’Œç›å€¼
                    string encryptedKeyBase64 = Convert.ToBase64String(encryptedKey);
                    string saltBase64 = Convert.ToBase64String(salt);
                    string ivBase64 = Convert.ToBase64String(aes.IV);
                    bool success = SetRegistryValue(Registry.CurrentUser, DOG_AES_KEY, encryptedKeyBase64);
                    success &= SetRegistryValue(Registry.CurrentUser, DOG_AES_SALT, saltBase64);
                    success &= SetRegistryValue(Registry.CurrentUser, DOG_AES_IV, ivBase64);
                    return success;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"生成应用绑定加密狗失败: {ex.Message}");
                return false;
            }
        }
        /// <summary>
        /// éªŒè¯å¹¶èŽ·å–åº”ç”¨ç»‘å®šå¯†é’¥
        /// </summary>
        public static (byte[] Key, byte[] IV) GetAppBoundKey(string expectedAppIdentifier)
        {
            try
            {
                string encryptedKeyBase64 = GetRegistryValue(DOG_AES_KEY);
                string saltBase64 = GetRegistryValue(DOG_AES_SALT);
                string ivBase64 = GetRegistryValue(DOG_AES_IV);
                if (string.IsNullOrEmpty(encryptedKeyBase64) || string.IsNullOrEmpty(saltBase64) || string.IsNullOrEmpty(ivBase64))
                {
                    return (null, null);
                }
                byte[] encryptedKey = Convert.FromBase64String(encryptedKeyBase64);
                byte[] salt = Convert.FromBase64String(saltBase64);
                byte[] iv = Convert.FromBase64String(ivBase64);
                // éªŒè¯åº”用标识符
                string storedAppIdentifier = Encoding.UTF8.GetString(salt);
                if (storedAppIdentifier != expectedAppIdentifier)
                {
                    return (null, null);
                }
                // è§£å¯†å¯†é’¥
                byte[] key = DecryptKeyWithSalt(encryptedKey, salt, iv);
                return (key, iv);
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"获取应用绑定密钥失败: {ex.Message}");
                return (null, null);
            }
        }
        private static byte[] EncryptKeyWithSalt(byte[] key, byte[] salt, byte[] iv)
        {
            using (var deriveBytes = new Rfc2898DeriveBytes(key, salt, 10000, HashAlgorithmName.SHA256))
            {
                byte[] derivedKey = deriveBytes.GetBytes(32); // AES-256
                                                              // è¿™é‡Œå¯ä»¥æ·»åŠ é¢å¤–çš„åŠ å¯†é€»è¾‘
                return derivedKey;
            }
        }
        private static byte[] DecryptKeyWithSalt(byte[] encryptedKey, byte[] salt, byte[] iv)
        {
            // åå‘解密过程
            using (var deriveBytes = new Rfc2898DeriveBytes(encryptedKey, salt, 10000, HashAlgorithmName.SHA256))
            {
                return deriveBytes.GetBytes(32);
            }
        }
        /// <summary>
        /// ä½¿ç”¨åŠ å¯†ç‹—ä¸­çš„å¯†é’¥åŠ å¯†æ•°æ®
        /// </summary>
        public static string EncryptWithDog(string plainText)
        {
            var (key, iv) = GetAesParameters();
            if (key == null || iv == null)
                throw new InvalidOperationException("未找到有效的加密狗");
            using (Aes aes = Aes.Create())
            {
                aes.Key = key;
                aes.IV = iv;
                ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
                using (var ms = new MemoryStream())
                using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    using (var sw = new StreamWriter(cs))
                    {
                        sw.Write(plainText);
                    }
                    return Convert.ToBase64String(ms.ToArray());
                }
            }
        }
        /// <summary>
        /// ä½¿ç”¨åŠ å¯†ç‹—ä¸­çš„å¯†é’¥è§£å¯†æ•°æ®
        /// </summary>
        public static string DecryptWithDog(string cipherText)
        {
            var (key, iv) = GetAesParameters();
            if (key == null || iv == null)
                throw new InvalidOperationException("未找到有效的加密狗");
            using (Aes aes = Aes.Create())
            {
                aes.Key = key;
                aes.IV = iv;
                ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
                byte[] cipherBytes = Convert.FromBase64String(cipherText);
                using (var ms = new MemoryStream(cipherBytes))
                using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                using (var sr = new StreamReader(cs))
                {
                    return sr.ReadToEnd();
                }
            }
        }
        /// <summary>
        /// æ³¨å†ŒåŠ å¯†ç‹—
        /// </summary>
        public static bool RegistrationDog()
        {
            Debug.WriteLine("正在生成AES加密狗...");
            if (GenerateAppBoundDog("VisionUltra"))
            {
                Debug.WriteLine("AES加密狗生成成功!");
                // å»ºè®®ç”¨æˆ·å¤‡ä»½è¿™äº›å€¼
                Debug.WriteLine("\n请妥善保存以上密钥信息!");
                return true;
            }
            else
            {
                Debug.WriteLine("加密狗生成失败,请以管理员身份运行");
                return false;
            }
        }
        /// <summary>
        /// æ£€æŸ¥è½¯åŠ å¯†ç‹—
        /// </summary>
        /// <returns></returns>
        public static bool CheckDog()
        {
            if (!ValidateAesDog())
            {
                Debug.WriteLine("未找到有效的AES加密狗");
                return false;
            }
            Debug.WriteLine("AES加密狗验证成功");
            return true;
        }
        #endregion
        /// <summary>
        /// å¤åˆ¶æ–‡ä»¶å¤¹åŠå…¶å†…容
        /// </summary>
        /// <param name="sourceDir"></param>
        /// <param name="destDir"></param>
        /// <returns></returns>
        public static bool CopyDirectory(string sourceDir, string destDir)
        {
            try
            {
                // æ£€æŸ¥ç›®æ ‡æ–‡ä»¶å¤¹æ˜¯å¦å­˜åœ¨ï¼Œå¦‚果不存在,则创建它
                if (!Directory.Exists(destDir))
                {
                    Directory.CreateDirectory(destDir);
                }
                // å¤åˆ¶æ‰€æœ‰æ–‡ä»¶åˆ°ç›®æ ‡æ–‡ä»¶å¤¹
                foreach (string file in Directory.GetFiles(sourceDir))
                {
                    string destFile = Path.Combine(destDir, Path.GetFileName(file));
                    File.Copy(file, destFile, true); // ç¬¬ä¸‰ä¸ªå‚数为 true,表示如果文件已存在,则覆盖它
                }
                // é€’归复制所有子文件夹
                foreach (string subDir in Directory.GetDirectories(sourceDir))
                {
                    string destSubDir = Path.Combine(destDir, Path.GetFileName(subDir));
                    CopyDirectory(subDir, destSubDir); // é€’归调用复制子文件夹
                }
                return true;
            }
            catch { return false; }
        }
        /// <summary>
        /// é‡å‘½åæ–‡ä»¶å¤¹
        /// </summary>
        /// <param name="oldDir"></param>
        /// <param name="newDir"></param>
        /// <returns></returns>
        public static bool RenameDirectory(string oldDir, string newDir)
        {
            try
            {
                // é‡å‘½åæ–‡ä»¶å¤¹
                if (Directory.Exists(oldDir))
                {
                    Directory.Move(oldDir, newDir);
                    return true;
                }
                Debug.WriteLine($"文件不存在: {oldDir}");
                return false;
            }
            catch { return false; }
        }
        /// <summary>
        /// é‡å‘½åæ–‡ä»¶
        /// </summary>
        /// <param name="oldFile"></param>
        /// <param name="newFile"></param>
        /// <returns></returns>
        public static bool RenameFile(string oldFile, string newFile)
        {
            try
            {
                if (!File.Exists(newFile))
                {
                    // é‡å‘½åæ–‡ä»¶
                    File.Move(oldFile, newFile);
                    Debug.WriteLine($"文件已重命名: {oldFile} -> {newFile}");
                    return true;
                }
                Debug.WriteLine($"文件不存在: {oldFile}");
                return false;
            }
            catch { return false; }
        }
        #region è¯»å†™åˆ°exe.Config文件
        public static void WriteConfig(string node, string value)
        {
            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (config.AppSettings.Settings[node] == null)
            {
                config.AppSettings.Settings.Add(node, value);
            }
            else
            {
                config.AppSettings.Settings[node].Value = value;
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");//重新加载新的配置文件
        }
        public static bool ReadStringConfig(string node, out string result)
        {
            result = "";
            try
            {
                if (ConfigurationManager.AppSettings[node] != null)
                {
                    result = ConfigurationManager.AppSettings[node].ToString();
                    if (result == null)
                    {
                        WriteConfig(node, "");
                        result = "";
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                WriteConfig(node, "");
                result = "";
                return false;
            }
        }
        public static bool ReadBoolenConfig(string node, out bool result)
        {
            result = false;
            try
            {
                result = Convert.ToBoolean(ConfigurationManager.AppSettings[node]);
                if (result == null)
                {
                    WriteConfig(node, (false).ToString());
                    result = false;
                    return false;
                }
                else
                    return true;
            }
            catch
            {
                WriteConfig(node, (false).ToString());
                result = false;
                return false;
            }
        }
        #endregion
    }
}
LB_SmartVision/VisionForm.Designer.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,369 @@
namespace LB_SmartVision
{
    partial class VisionForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;
        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        #region Windows Form Designer generated code
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VisionForm));
            theme_VisionForm = new ReaLTaiizor.Forms.ThemeForm();
            sc_VisionForm = new SplitContainer();
            sc_VisionMainViewer = new SplitContainer();
            tlp_VisionMainForm = new Sunny.UI.UITableLayoutPanel();
            tlp_VisionMainOperator = new Sunny.UI.UITableLayoutPanel();
            ckb_AllowRun = new Sunny.UI.UICheckBox();
            btn_Login = new ReaLTaiizor.Controls.Button();
            btn_GlobalVar = new ReaLTaiizor.Controls.Button();
            com_ProductName = new ReaLTaiizor.Controls.AloneComboBox();
            materialTabSelector = new MaterialSkin.Controls.MaterialTabSelector();
            materialTabControl = new MaterialSkin.Controls.MaterialTabControl();
            tabPage1 = new TabPage();
            tabPage2 = new TabPage();
            grb_Info = new Sunny.UI.UIGroupBox();
            rich_Info = new Sunny.UI.UIRichTextBox();
            cb_VisionForm = new ReaLTaiizor.Controls.ControlBox();
            theme_VisionForm.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)sc_VisionForm).BeginInit();
            sc_VisionForm.Panel1.SuspendLayout();
            sc_VisionForm.Panel2.SuspendLayout();
            sc_VisionForm.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)sc_VisionMainViewer).BeginInit();
            sc_VisionMainViewer.Panel1.SuspendLayout();
            sc_VisionMainViewer.Panel2.SuspendLayout();
            sc_VisionMainViewer.SuspendLayout();
            tlp_VisionMainForm.SuspendLayout();
            tlp_VisionMainOperator.SuspendLayout();
            materialTabControl.SuspendLayout();
            grb_Info.SuspendLayout();
            SuspendLayout();
            //
            // theme_VisionForm
            //
            theme_VisionForm.BackColor = Color.FromArgb(32, 41, 50);
            theme_VisionForm.Controls.Add(sc_VisionForm);
            theme_VisionForm.Controls.Add(cb_VisionForm);
            theme_VisionForm.Dock = DockStyle.Fill;
            theme_VisionForm.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Regular, GraphicsUnit.Point, 0);
            theme_VisionForm.Image = (Image)resources.GetObject("theme_VisionForm.Image");
            theme_VisionForm.Location = new Point(0, 0);
            theme_VisionForm.Name = "theme_VisionForm";
            theme_VisionForm.Padding = new Padding(10, 70, 10, 9);
            theme_VisionForm.RoundCorners = true;
            theme_VisionForm.Sizable = true;
            theme_VisionForm.Size = new Size(1440, 960);
            theme_VisionForm.SmartBounds = true;
            theme_VisionForm.StartPosition = FormStartPosition.WindowsDefaultLocation;
            theme_VisionForm.TabIndex = 0;
            theme_VisionForm.Text = "轮胎外观视觉检测系统";
            //
            // sc_VisionForm
            //
            sc_VisionForm.Dock = DockStyle.Fill;
            sc_VisionForm.Location = new Point(10, 70);
            sc_VisionForm.Name = "sc_VisionForm";
            sc_VisionForm.Orientation = Orientation.Horizontal;
            //
            // sc_VisionForm.Panel1
            //
            sc_VisionForm.Panel1.Controls.Add(sc_VisionMainViewer);
            //
            // sc_VisionForm.Panel2
            //
            sc_VisionForm.Panel2.Controls.Add(grb_Info);
            sc_VisionForm.Size = new Size(1420, 881);
            sc_VisionForm.SplitterDistance = 699;
            sc_VisionForm.TabIndex = 1;
            //
            // sc_VisionMainViewer
            //
            sc_VisionMainViewer.Dock = DockStyle.Fill;
            sc_VisionMainViewer.Location = new Point(0, 0);
            sc_VisionMainViewer.Name = "sc_VisionMainViewer";
            sc_VisionMainViewer.Orientation = Orientation.Horizontal;
            //
            // sc_VisionMainViewer.Panel1
            //
            sc_VisionMainViewer.Panel1.Controls.Add(tlp_VisionMainForm);
            //
            // sc_VisionMainViewer.Panel2
            //
            sc_VisionMainViewer.Panel2.Controls.Add(materialTabControl);
            sc_VisionMainViewer.Size = new Size(1420, 699);
            sc_VisionMainViewer.SplitterDistance = 100;
            sc_VisionMainViewer.TabIndex = 0;
            //
            // tlp_VisionMainForm
            //
            tlp_VisionMainForm.BackColor = Color.FromArgb(39, 51, 63);
            tlp_VisionMainForm.ColumnCount = 1;
            tlp_VisionMainForm.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            tlp_VisionMainForm.Controls.Add(tlp_VisionMainOperator, 0, 1);
            tlp_VisionMainForm.Controls.Add(materialTabSelector, 0, 0);
            tlp_VisionMainForm.Dock = DockStyle.Fill;
            tlp_VisionMainForm.Location = new Point(0, 0);
            tlp_VisionMainForm.Name = "tlp_VisionMainForm";
            tlp_VisionMainForm.RowCount = 2;
            tlp_VisionMainForm.RowStyles.Add(new RowStyle(SizeType.Absolute, 61F));
            tlp_VisionMainForm.RowStyles.Add(new RowStyle(SizeType.Absolute, 39F));
            tlp_VisionMainForm.Size = new Size(1420, 100);
            tlp_VisionMainForm.TabIndex = 0;
            tlp_VisionMainForm.TagString = null;
            //
            // tlp_VisionMainOperator
            //
            tlp_VisionMainOperator.BackColor = Color.FromArgb(39, 51, 63);
            tlp_VisionMainOperator.ColumnCount = 9;
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.11111F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 11.1111107F));
            tlp_VisionMainOperator.Controls.Add(ckb_AllowRun, 0, 0);
            tlp_VisionMainOperator.Controls.Add(btn_Login, 1, 0);
            tlp_VisionMainOperator.Controls.Add(btn_GlobalVar, 7, 0);
            tlp_VisionMainOperator.Controls.Add(com_ProductName, 8, 0);
            tlp_VisionMainOperator.Dock = DockStyle.Fill;
            tlp_VisionMainOperator.Location = new Point(3, 64);
            tlp_VisionMainOperator.Name = "tlp_VisionMainOperator";
            tlp_VisionMainOperator.RowCount = 1;
            tlp_VisionMainOperator.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            tlp_VisionMainOperator.Size = new Size(1414, 33);
            tlp_VisionMainOperator.TabIndex = 0;
            tlp_VisionMainOperator.TagString = null;
            //
            // ckb_AllowRun
            //
            ckb_AllowRun.Dock = DockStyle.Fill;
            ckb_AllowRun.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            ckb_AllowRun.ForeColor = SystemColors.Control;
            ckb_AllowRun.Location = new Point(3, 3);
            ckb_AllowRun.MinimumSize = new Size(1, 1);
            ckb_AllowRun.Name = "ckb_AllowRun";
            ckb_AllowRun.Size = new Size(151, 27);
            ckb_AllowRun.TabIndex = 2;
            ckb_AllowRun.Text = "运行模式";
            //
            // btn_Login
            //
            btn_Login.BackColor = Color.Transparent;
            btn_Login.BorderColor = Color.FromArgb(32, 34, 37);
            btn_Login.Dock = DockStyle.Fill;
            btn_Login.EnteredBorderColor = Color.FromArgb(165, 37, 37);
            btn_Login.EnteredColor = Color.FromArgb(32, 34, 37);
            btn_Login.Font = new Font("Microsoft Sans Serif", 12F);
            btn_Login.Image = null;
            btn_Login.ImageAlign = ContentAlignment.MiddleLeft;
            btn_Login.InactiveColor = Color.FromArgb(32, 34, 37);
            btn_Login.Location = new Point(160, 3);
            btn_Login.Name = "btn_Login";
            btn_Login.PressedBorderColor = Color.FromArgb(165, 37, 37);
            btn_Login.PressedColor = Color.FromArgb(165, 37, 37);
            btn_Login.Size = new Size(151, 27);
            btn_Login.TabIndex = 3;
            btn_Login.Text = "用户登录";
            btn_Login.TextAlignment = StringAlignment.Center;
            //
            // btn_GlobalVar
            //
            btn_GlobalVar.BackColor = Color.Gray;
            btn_GlobalVar.BorderColor = Color.FromArgb(32, 34, 37);
            btn_GlobalVar.Dock = DockStyle.Fill;
            btn_GlobalVar.EnteredBorderColor = Color.FromArgb(165, 37, 37);
            btn_GlobalVar.EnteredColor = Color.FromArgb(32, 34, 37);
            btn_GlobalVar.Font = new Font("Microsoft Sans Serif", 12F);
            btn_GlobalVar.Image = null;
            btn_GlobalVar.ImageAlign = ContentAlignment.MiddleLeft;
            btn_GlobalVar.InactiveColor = Color.FromArgb(32, 34, 37);
            btn_GlobalVar.Location = new Point(1102, 3);
            btn_GlobalVar.Name = "btn_GlobalVar";
            btn_GlobalVar.PressedBorderColor = Color.FromArgb(165, 37, 37);
            btn_GlobalVar.PressedColor = Color.FromArgb(165, 37, 37);
            btn_GlobalVar.Size = new Size(151, 27);
            btn_GlobalVar.TabIndex = 4;
            btn_GlobalVar.Text = "全局变量";
            btn_GlobalVar.TextAlignment = StringAlignment.Center;
            //
            // com_ProductName
            //
            com_ProductName.Dock = DockStyle.Fill;
            com_ProductName.DrawMode = DrawMode.OwnerDrawFixed;
            com_ProductName.DropDownStyle = ComboBoxStyle.DropDownList;
            com_ProductName.EnabledCalc = true;
            com_ProductName.FormattingEnabled = true;
            com_ProductName.ItemHeight = 20;
            com_ProductName.Location = new Point(1259, 3);
            com_ProductName.Name = "com_ProductName";
            com_ProductName.Size = new Size(152, 26);
            com_ProductName.TabIndex = 5;
            //
            // materialTabSelector
            //
            materialTabSelector.BaseTabControl = materialTabControl;
            materialTabSelector.Depth = 0;
            materialTabSelector.Dock = DockStyle.Fill;
            materialTabSelector.Location = new Point(3, 3);
            materialTabSelector.MouseState = MaterialSkin.MouseState.HOVER;
            materialTabSelector.Name = "materialTabSelector";
            materialTabSelector.Size = new Size(1414, 55);
            materialTabSelector.TabIndex = 1;
            //
            // materialTabControl
            //
            materialTabControl.AccessibleRole = AccessibleRole.Sound;
            materialTabControl.Controls.Add(tabPage1);
            materialTabControl.Controls.Add(tabPage2);
            materialTabControl.Depth = 0;
            materialTabControl.Dock = DockStyle.Fill;
            materialTabControl.Location = new Point(0, 0);
            materialTabControl.MouseState = MaterialSkin.MouseState.HOVER;
            materialTabControl.Name = "materialTabControl";
            materialTabControl.SelectedIndex = 0;
            materialTabControl.Size = new Size(1420, 595);
            materialTabControl.TabIndex = 0;
            //
            // tabPage1
            //
            tabPage1.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
            tabPage1.Location = new Point(4, 30);
            tabPage1.Name = "tabPage1";
            tabPage1.Size = new Size(1412, 561);
            tabPage1.TabIndex = 0;
            tabPage1.Text = "tabPage1";
            tabPage1.UseVisualStyleBackColor = true;
            //
            // tabPage2
            //
            tabPage2.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134);
            tabPage2.Location = new Point(4, 26);
            tabPage2.Name = "tabPage2";
            tabPage2.Size = new Size(1412, 565);
            tabPage2.TabIndex = 1;
            tabPage2.Text = "tabPage2";
            tabPage2.UseVisualStyleBackColor = true;
            //
            // grb_Info
            //
            grb_Info.Controls.Add(rich_Info);
            grb_Info.Dock = DockStyle.Fill;
            grb_Info.FillColor = Color.FromArgb(32, 41, 50);
            grb_Info.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            grb_Info.ForeColor = SystemColors.Control;
            grb_Info.Location = new Point(0, 0);
            grb_Info.Margin = new Padding(4, 5, 4, 5);
            grb_Info.MinimumSize = new Size(1, 1);
            grb_Info.Name = "grb_Info";
            grb_Info.Padding = new Padding(0, 32, 0, 0);
            grb_Info.Size = new Size(1420, 178);
            grb_Info.TabIndex = 1;
            grb_Info.Text = "日志显示区:";
            grb_Info.TextAlignment = ContentAlignment.MiddleLeft;
            //
            // rich_Info
            //
            rich_Info.Dock = DockStyle.Fill;
            rich_Info.FillColor = Color.FromArgb(32, 41, 50);
            rich_Info.Font = new Font("宋体", 12F, FontStyle.Regular, GraphicsUnit.Point, 134);
            rich_Info.Location = new Point(0, 32);
            rich_Info.Margin = new Padding(4, 5, 4, 5);
            rich_Info.MinimumSize = new Size(1, 1);
            rich_Info.Name = "rich_Info";
            rich_Info.Padding = new Padding(2);
            rich_Info.ShowText = false;
            rich_Info.Size = new Size(1420, 146);
            rich_Info.TabIndex = 0;
            rich_Info.TextAlignment = ContentAlignment.MiddleLeft;
            //
            // cb_VisionForm
            //
            cb_VisionForm.Anchor = AnchorStyles.Top | AnchorStyles.Right;
            cb_VisionForm.BackColor = Color.FromArgb(32, 34, 37);
            cb_VisionForm.CloseHoverColor = Color.FromArgb(230, 17, 35);
            cb_VisionForm.DefaultLocation = true;
            cb_VisionForm.EnableHoverHighlight = true;
            cb_VisionForm.EnableMaximizeButton = true;
            cb_VisionForm.EnableMinimizeButton = true;
            cb_VisionForm.ForeColor = Color.FromArgb(155, 155, 155);
            cb_VisionForm.Location = new Point(1340, 18);
            cb_VisionForm.MaximizeHoverColor = Color.FromArgb(74, 74, 74);
            cb_VisionForm.MinimizeHoverColor = Color.FromArgb(63, 63, 65);
            cb_VisionForm.Name = "cb_VisionForm";
            cb_VisionForm.Size = new Size(90, 25);
            cb_VisionForm.TabIndex = 0;
            cb_VisionForm.Text = "controlBox1";
            //
            // VisionForm
            //
            AutoScaleDimensions = new SizeF(96F, 96F);
            AutoScaleMode = AutoScaleMode.Dpi;
            ClientSize = new Size(1440, 960);
            Controls.Add(theme_VisionForm);
            FormBorderStyle = FormBorderStyle.None;
            Icon = (Icon)resources.GetObject("$this.Icon");
            MinimumSize = new Size(261, 61);
            Name = "VisionForm";
            Text = "轮胎外观视觉检测系统";
            TransparencyKey = Color.Fuchsia;
            Load += VisionForm_Load;
            theme_VisionForm.ResumeLayout(false);
            sc_VisionForm.Panel1.ResumeLayout(false);
            sc_VisionForm.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)sc_VisionForm).EndInit();
            sc_VisionForm.ResumeLayout(false);
            sc_VisionMainViewer.Panel1.ResumeLayout(false);
            sc_VisionMainViewer.Panel2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)sc_VisionMainViewer).EndInit();
            sc_VisionMainViewer.ResumeLayout(false);
            tlp_VisionMainForm.ResumeLayout(false);
            tlp_VisionMainOperator.ResumeLayout(false);
            materialTabControl.ResumeLayout(false);
            grb_Info.ResumeLayout(false);
            ResumeLayout(false);
        }
        #endregion
        private ReaLTaiizor.Forms.ThemeForm theme_VisionForm;
        private ReaLTaiizor.Controls.ControlBox cb_VisionForm;
        private SplitContainer sc_VisionForm;
        private SplitContainer sc_VisionMainViewer;
        private Sunny.UI.UITableLayoutPanel tlp_VisionMainOperator;
        private Sunny.UI.UICheckBox ckb_AllowRun;
        private ReaLTaiizor.Controls.Button btn_Login;
        private ReaLTaiizor.Controls.Button btn_GlobalVar;
        private Sunny.UI.UITableLayoutPanel tlp_VisionMainForm;
        private Sunny.UI.UIGroupBox grb_Info;
        private Sunny.UI.UIRichTextBox rich_Info;
        private MaterialSkin.Controls.MaterialTabControl materialTabControl;
        private ReaLTaiizor.Controls.AloneComboBox com_ProductName;
        private MaterialSkin.Controls.MaterialTabSelector materialTabSelector;
        private TabPage tabPage1;
        private TabPage tabPage2;
    }
}
LB_SmartVision/VisionForm.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,997 @@
using HalconDotNet;
using LB_SmartVision.Forms.Pages;
using LB_SmartVision.Forms.Pages.CameraPage;
using LB_SmartVision.Forms.Pages.CommunicatorPage;
using LB_SmartVision.Forms.Pages.MESPage;
using LB_SmartVision.Forms.Pages.MotionControlPage;
using LB_SmartVision.Forms.Pages.ProcessPage;
using LB_SmartVision.Forms.Pages.SettingPage;
using LB_SmartVision.Forms.Pages.UserManagementPage;
using LB_SmartVision.ProcessRun;
using LB_SmartVision.Tool;
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Communicators.TCom;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Sunny.UI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision
{
    public partial class VisionForm : Form
    {
        AllProcessesPage AllProcessesPage = new AllProcessesPage();
        CamerasEditPage CamerasEditPage = new CamerasEditPage();
        CommunicatorsEditPage CommunicatorsEditPage = new CommunicatorsEditPage();
        SettingEditPage SettingEditPage = new SettingEditPage();
        MESEditPage MESEditPage = new MESEditPage();
        MotionControlEditPage MotionControlEditPage = new MotionControlEditPage();
        UserManagementEditPage UserManagementEditPage = new UserManagementEditPage();
        byte[] Assembly_LB_VisionProcessesBytes = File.ReadAllBytes("LB_VisionProcesses.dll");
        /// <summary>
        /// ç”¨äºŽååºåˆ—化的程序集引用
        /// </summary>
        Assembly Assembly_LB_VisionProcessesDll = null;
        public VisionForm()
        {
            InitializeComponent();
            HOperatorSet.SetWindowAttr("background_color", "gray");
            Assembly_LB_VisionProcessesDll = Assembly.Load(Assembly_LB_VisionProcessesBytes);
            GlobalVar.dicCommunicators.DictionaryChanged += CommunicatorsChanged;
            GlobalVar.dicProcesses.DictionaryChanged += ProcessRunBllChanged;
            //最开始就清空所有Tab页
            materialTabControl.TabPages.Clear();
            materialTabControl.Controls.Add(AllProcessesPage);
            CamerasEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(CamerasEditPage));
            CommunicatorsEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(CommunicatorsEditPage));
            SettingEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(SettingEditPage));
            MESEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(MESEditPage));
            MotionControlEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(MotionControlEditPage));
            UserManagementEditPage.LogInfo += LogInfo;
            materialTabControl.Controls.Add(new MyPage(UserManagementEditPage));
            for (int i = 0; i < materialTabControl.TabPages.Count; i++)
            {
                //materialTabControl.TabPages[i].Font= new Font("Microsoft YaHei UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0);
            }
            materialTabSelector.BaseTabControl = materialTabControl;
            //materialTabSelector.Font = new Font("Microsoft YaHei UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0);
        }
        private void ProcessRunBllChanged(object? sender, DictionaryChangedEventArgs<string, ProcessRunBll> e)
        {
            try
            {
                string msg = string.Empty;
                List<MyPage> removeMyPage = new List<MyPage>();
                switch (e.ChangeType)
                {
                    case DictionaryChangeType.Added:
                        string AddProcessName = e.NewKey;
                        GlobalVar.dicProcesses[AddProcessName].LogInfo += LogInfo;
                        if (GlobalVar.dicProcesses[AddProcessName].Load(out msg))
                        {
                            LogInfo($"流程[{AddProcessName}]加载成功", LogInfoType.PASS);
                            IProcess.dicGlobalVars.TryAdd($"{AddProcessName}.Result", false);
                            IProcess.dicGlobalVars.TryAdd($"{AddProcessName}.Msg", "");
                            ProcessRunBll processRunBll = GlobalVar.dicProcesses[AddProcessName];
                            ProcessPage ProcessPage = new ProcessPage(processRunBll.Name, processRunBll);
                            ProcessPage.LogInfo += LogInfo;
                            if (materialTabControl.InvokeRequired)
                            {
                                materialTabControl.Invoke(new Action(() =>
                                {
                                    materialTabControl.Controls.Add(new MyPage(ProcessPage));
                                }));
                            }
                            else
                                materialTabControl.Controls.Add(new MyPage(ProcessPage));
                        }
                        else
                            LogInfo($"流程[{AddProcessName}]加载失败,原因是{msg}", LogInfoType.ERROR);
                        LogInfo($"添加流程[{AddProcessName}]", LogInfoType.INFO);
                        break;
                    case DictionaryChangeType.Removed:
                        string RemoveProcessName = e.OldKey;
                        foreach (var control in materialTabControl.Controls)
                        {
                            if (control != null && control is MyPage && ((MyPage)control).UserControl is ProcessPage processPage)
                            {
                                if (processPage.Text == RemoveProcessName)
                                {
                                    IProcess.dicGlobalVars.TryRemove($"{RemoveProcessName}.Result", out _);
                                    IProcess.dicGlobalVars.TryRemove($"{RemoveProcessName}.Msg", out _);
                                    processPage.LogInfo -= LogInfo;
                                    removeMyPage.Add((MyPage)control);
                                }
                            }
                        }
                        foreach (var myPage in removeMyPage)
                        {
                            if (materialTabControl.InvokeRequired)
                            {
                                materialTabControl.Invoke(new Action(() =>
                                {
                                    materialTabControl.Controls.Remove(myPage);
                                }));
                            }
                            else
                                materialTabControl.Controls.Remove(myPage);
                        }
                        LogInfo($"移除流程[{RemoveProcessName}]", LogInfoType.INFO);
                        break;
                    case DictionaryChangeType.Renamed:
                        string OldProcessName = e.OldKey;
                        string NewProcessName = e.NewKey;
                        try
                        {
                            IProcess.dicGlobalVars.TryRemove($"{OldProcessName}.Result", out object obj1);
                            IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Result", obj1);
                            IProcess.dicGlobalVars.TryRemove($"{OldProcessName}.Msg", out object obj2);
                            IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Msg", obj2);
                        }
                        catch { }
                        LB_SmartVision.Tool.Tool.RenameDirectory(GlobalVar.allProcessPath + "\\" + OldProcessName
                            , GlobalVar.allProcessPath + "\\" + NewProcessName);
                        e.NewValue.Name = NewProcessName;
                        foreach (var control in materialTabControl.Controls)
                        {
                            if (control != null && control is MyPage && ((MyPage)control).UserControl is ProcessPage)
                            {
                                ProcessPage processPage = ((MyPage)control).UserControl as ProcessPage;
                                if (processPage.Text == OldProcessName)
                                {
                                    if (materialTabControl.InvokeRequired)
                                    {
                                        materialTabControl.Invoke(new Action(() =>
                                        {
                                            materialTabControl.Controls.Remove((MyPage)control);
                                        }));
                                    }
                                    else
                                        materialTabControl.Controls.Remove((MyPage)control);
                                    if (GlobalVar.dicProcesses[NewProcessName].Load(out msg))
                                    {
                                        LogInfo($"流程[{NewProcessName}]重命名后加载成功", LogInfoType.PASS);
                                        IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Result", false);
                                        IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Msg", "");
                                        ProcessRunBll processRunBll = GlobalVar.dicProcesses[NewProcessName];
                                        ProcessPage ProcessPage = new ProcessPage(processRunBll.Name, processRunBll);
                                        ProcessPage.LogInfo += LogInfo;
                                        if (materialTabControl.InvokeRequired)
                                        {
                                            materialTabControl.Invoke(new Action(() =>
                                            {
                                                materialTabControl.Controls.Add(new MyPage(ProcessPage));
                                            }));
                                        }
                                        else
                                            materialTabControl.Controls.Add(new MyPage(ProcessPage));
                                    }
                                    else
                                        LogInfo($"流程[{NewProcessName}]重命名后加载失败,原因是{msg}", LogInfoType.ERROR);
                                }
                            }
                        }
                        LogInfo(string.Format("重命名流程名[{0}]修改为[{1}]", OldProcessName, NewProcessName), LogInfoType.INFO);
                        break;
                }
            }
            catch { }
        }
        private void CommunicatorsChanged(object? sender, DictionaryChangedEventArgs<string, BaseCommunicator> e)
        {
        }
        private void LogInfo(string arg1, LogInfoType type)
        {
        }
        public static bool SaveAllLayout()
        {
            try
            {
                string strJson = string.Empty;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.dicLayout, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allLayoutPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allLayoutPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
        }
        public static bool LoadAllCsv(string allCsvPath)
        {
            try
            {
                if (!File.Exists(allCsvPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allCsvPath);
                    SaveAllCsv();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allCsvPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                GlobalVar.dicCsvSetting.Clear();
                GlobalVar.dicCsvSetting = JsonConvert.DeserializeObject<ConcurrentDictionary<string, CsvSetting>>(strJson);
                if (GlobalVar.dicCsvSetting == null)
                {
                    GlobalVar.dicCsvSetting = new ConcurrentDictionary<string, CsvSetting>();
                    return false;
                }
                return true;
            }
            catch { return false; }
        }
        public static bool SaveAllCsv()
        {
            try
            {
                string strJson = string.Empty;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.dicCsvSetting, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allCsvPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allCsvPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
        }
        public bool LoadAllProcessSetting(string allProcessSettingStringPath)
        {
            try
            {
                if (!File.Exists(allProcessSettingStringPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allProcessSettingStringPath);
                    SaveAllProcessSetting();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allProcessSettingStringPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                GlobalVar.dicProcessSetting = JsonConvert.DeserializeObject<ConcurrentDictionary<int, ConcurrentDictionary<string, string>>>(strJson);
                if (GlobalVar.dicProcessSetting == null)
                    GlobalVar.dicProcessSetting = new ConcurrentDictionary<int, ConcurrentDictionary<string, string>>();
                try
                {
                    string json = File.ReadAllText(GlobalVar.allRunSettingStringPath);
                    var settings = new JsonSerializerSettings
                    {
                        TypeNameHandling = TypeNameHandling.Auto // å¤„理多态类型
                    };
                    GlobalVar.ControlStates = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, settings);
                }
                catch { }
                return true;
            }
            catch { return false; }
        }
        public static bool SaveAllProcessSetting()
        {
            try
            {
                string strJson = string.Empty;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.dicProcessSetting, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessSettingStringPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allProcessSettingStringPath, strJson, Encoding.UTF8);
                //LogInfo($"流程设置保存成功", LogInfoType.INFO);
                return true;
            }
            catch { return false; }
        }
        private void VisionForm_Load(object sender, EventArgs e)
        {
            if (!LB_SmartVision.Tool.Tool.ReadStringConfig("数据库名称", out string DateBaseName))
            {
                DateBaseName = "产品0";
                LB_SmartVision.Tool.Tool.WriteConfig("数据库名称", DateBaseName);
                LB_SmartVision.Tool.Tool.WriteConfig("产品列表", DateBaseName);
            }
            LB_SmartVision.Tool.Tool.ReadStringConfig("User ID", out string User_ID);
            LB_SmartVision.Tool.Tool.ReadStringConfig("Password", out string Password);
            GlobalVar.strProductName = DateBaseName;
            //加载通讯
            foreach (BaseCommunicator com in GlobalVar.dicCommunicators.Values)
                com.Disconnect();
            GlobalVar.dicCommunicators.Clear();
            if (LoadAllCommunicators(GlobalVar.allCommunicatorsConnectionStringPath))
                LogInfo("通讯加载成功", LogInfoType.PASS);
            else
                LogInfo("通讯加载失败", LogInfoType.ERROR);
            //加载相机
            foreach (BaseCamera camera in GlobalVar.dicCameras.Values)
                camera.Dispose();
            GlobalVar.dicCameras.Clear();
            if (LoadAllCameras(GlobalVar.allCamerasConnectionStringPath))
                LogInfo("相机加载成功", LogInfoType.PASS);
            else
                LogInfo("相机加载失败", LogInfoType.ERROR);
            //必须先加载相机和通讯端口,因为流程加载过程中会用到相机和通讯口
            //加载全局变量
            IProcess.dicGlobalVars.Clear();
            if (LoadAllProcessVars(GlobalVar.allProcessVarsPath))
                LogInfo("全局变量加载成功", LogInfoType.PASS);
            else
                LogInfo("全局变量加载失败", LogInfoType.ERROR);
            //加载流程
            GlobalVar.dicProcesses.Clear();
            if (LoadAllProcess(GlobalVar.allProcessConnectionStringPath))
                LogInfo("流程加载成功", LogInfoType.PASS);
            else
                LogInfo("流程加载失败", LogInfoType.ERROR);
            //加载触发设置
            if (LoadAllProcessSetting(GlobalVar.allProcessSettingStringPath))
                LogInfo("流程设置加载成功", LogInfoType.PASS);
            else
                LogInfo("流程设置加载失败", LogInfoType.ERROR);
            //加载流程布局
            GlobalVar.dicLayout.Clear();
            if (LoadAllLayout(GlobalVar.allLayoutPath))
                LogInfo("流程布局加载成功", LogInfoType.PASS);
            else
                LogInfo("流程布局加载失败", LogInfoType.ERROR);
            //加载流程表格
            GlobalVar.dicCsvSetting.Clear();
            if (LoadAllCsv(GlobalVar.allCsvPath))
                LogInfo("流程表格加载成功", LogInfoType.PASS);
            else
                LogInfo("流程表格加载失败", LogInfoType.ERROR);
            //显示所有产品
            com_ProductName.Items.Clear();
            LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products);
            List<string> lstProduct = (Products.Split(',')).ToList();
            foreach (string DatabaseName in lstProduct)
                com_ProductName.Items.Add(DatabaseName);
            com_ProductName.Items.Add("新增");
            com_ProductName.Text = GlobalVar.strProductName;
        }
        public void SaveAllSetting()
        {
            SaveAllProcess();
            SaveAllProcessVars();
            SaveAllCommunicators();
            SaveAllCameras();
            SaveAllProcessSetting();
            SaveAllLayout();
            SaveAllCsv();
        }
        public bool LoadAllCameras(string allCamerasConnectionStringPath)
        {
            if (!File.Exists(allCamerasConnectionStringPath))
            {
                Debug.WriteLine("文件不存在创建空文件");
                // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                string directoryPath = Path.GetDirectoryName(allCamerasConnectionStringPath);
                SaveAllCameras();
                return true;
            }
            string strJson = string.Empty;
            using (StreamReader streamReader = new StreamReader(allCamerasConnectionStringPath, Encoding.UTF8))
            {
                strJson = streamReader.ReadToEnd();
                streamReader.Close();
            }
            GlobalVar.allCamerasConnectionString = JsonConvert.DeserializeObject<ConcurrentDictionary<string, string>>(strJson);
            if (GlobalVar.allCamerasConnectionString == null)
            {
                MessageBox.Show("相机加载失败!", "异常");
                return false;
            }
            BaseCamera camera = null;
            foreach (var CameraConnectionString in GlobalVar.allCamerasConnectionString)
            {
                Enum.TryParse<CameraBrand>(CameraConnectionString.Value, out CameraBrand brand);
                switch (brand)
                {
                    case CameraBrand.HRCamera:
                        //camera = new HRCamera();
                        break;
                    case CameraBrand.LBCamera:
                        //camera = new LBCamera();
                        break;
                    default:
                        MessageBox.Show($"[{CameraConnectionString.Key}]品牌不支持!", "异常");
                        continue;
                }
                camera.SN = CameraConnectionString.Key;
                if (!camera.InitDevice(CameraConnectionString.Key, this.Handle))
                {
                    LogInfo($"初始化相机[{CameraConnectionString.Key}]失败", LogInfoType.ERROR);
                    if (camera != null)
                        camera.isGrabbing = false;
                }
                GlobalVar.dicCameras.TryAdd(CameraConnectionString.Key, camera);
            }
            return true;
        }
        public bool SaveAllCameras()
        {
            try
            {
                string strJson = string.Empty;
                GlobalVar.allCamerasConnectionString = new ConcurrentDictionary<string, string>();
                foreach (var item in GlobalVar.dicCameras)
                {
                    string CameraSN = item.Value.SN;// "TCP"
                    string CameraBrand = item.Value.Brand.ToString();//"1111"
                    if (string.IsNullOrEmpty(CameraSN) || string.IsNullOrEmpty(CameraBrand))
                        break;
                    GlobalVar.allCamerasConnectionString.TryAdd(CameraSN, CameraBrand);
                }
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.allCamerasConnectionString, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allCamerasConnectionStringPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch (Exception)
                    { }
                }
                File.WriteAllText(GlobalVar.allCamerasConnectionStringPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
        }
        public bool LoadAllCommunicators(string allCommunicatorsConnectionStringPath)
        {
            try
            {
                if (!File.Exists(allCommunicatorsConnectionStringPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allCommunicatorsConnectionStringPath);
                    SaveAllCommunicators();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allCommunicatorsConnectionStringPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                GlobalVar.allCommunicatorsConnectionString = JsonConvert.DeserializeObject<ConcurrentDictionary<string, string>>(strJson);
                if (GlobalVar.allCommunicatorsConnectionString == null)
                {
                    MessageBox.Show("通讯端口加载失败!", "异常");
                    return false;
                }
                //清空通讯口会把所有通讯口断开连接
                GlobalVar.dicCommunicators.Clear();
                ConcurrentDictionary<string, string> clientsCommunicatorsConnectionString = new ConcurrentDictionary<string, string>();
                foreach (var CommunicatorConnectionString in GlobalVar.allCommunicatorsConnectionString)
                {
                    string CommunicatorName = CommunicatorConnectionString.Key;
                    string CommunicatorAddress = CommunicatorConnectionString.Value;
                    // å®šä¹‰æ­£åˆ™è¡¨è¾¾å¼ä»¥æå–协议、IP åœ°å€å’Œç«¯å£
                    //1.    \((.*?)\):\(和 \) æ˜¯ç”¨äºŽåŒ¹é…æ‹¬å·çš„转义字符。
                    //      (.*?) æ˜¯ä¸€ä¸ªéžè´ªå©ªçš„匹配,用来匹配类名(MyProcesses.Communicators.TCPServer æˆ– MyProcesses.Communicators.UARTPort)。
                    //2.    ([^:] +):匹配冒号之前的部分,即地址(127.0.0.1 æˆ– COM5)。这里使用了[^:] æ¥åŒ¹é…é™¤äº†å†’号之外的任意字符。
                    //3.    (\d +) ï¼šåŒ¹é…ç«¯å£å·ï¼Œç¡®ä¿å®ƒåŒ¹é…ä¸€ä¸ªæˆ–多个数字。
                    string pattern = @"^\((?<ClassName>[^)]+)\)\[(?<IP>[^]]+)\]\[(?<PORT>[^]]+)\]$";
                    Match match = Regex.Match(CommunicatorAddress, pattern);
                    if (match.Success)
                    {
                        string ClassName = match.Groups["ClassName"].Value;   // "TCP"
                        string IP = match.Groups["IP"].Value;          // "127.0.0.1"
                        string PORT = match.Groups["PORT"].Value;        // "1111"
                        if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
                            break;
                        //利用反射创建实例
                        Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
                        if (type == null)
                        {
                            Debug.WriteLine("Class not found.");
                            return false;
                        }
                        var Communicator = Activator.CreateInstance(type, CommunicatorName) as BaseCommunicator;
                        if (Communicator == null)
                        {
                            Debug.WriteLine("BaseCommunicator not found.");
                            return false;
                        }
                        //TCP客户端最后再连接
                        if (Communicator is TCPClient)
                        {
                            clientsCommunicatorsConnectionString.TryAdd(CommunicatorConnectionString.Key, CommunicatorConnectionString.Value);
                            continue;
                        }
                        Communicator.CommunicatorConnections.Add("地址", IP);
                        Communicator.CommunicatorConnections.Add("端口", PORT);
                        Communicator.CommunicatorName = CommunicatorName;
                        if (!Communicator.Connect())
                            LogInfo($"初始化通讯口[{CommunicatorName}]失败,原因是{Communicator.Msg}", LogInfoType.ERROR);
                        else
                            LogInfo($"初始化通讯口[{CommunicatorName}]成功", LogInfoType.PASS);
                        GlobalVar.dicCommunicators.TryAdd(CommunicatorName, Communicator);
                    }
                    else
                    {
                        Debug.WriteLine("No match found.");
                    }
                }
                //TCP客户端最后连接
                foreach (var CommunicatorConnectionString in clientsCommunicatorsConnectionString)
                {
                    string CommunicatorName = CommunicatorConnectionString.Key;
                    string CommunicatorAddress = CommunicatorConnectionString.Value;
                    // å®šä¹‰æ­£åˆ™è¡¨è¾¾å¼ä»¥æå–协议、IP åœ°å€å’Œç«¯å£
                    //1.    \((.*?)\):\(和 \) æ˜¯ç”¨äºŽåŒ¹é…æ‹¬å·çš„转义字符。
                    //      (.*?) æ˜¯ä¸€ä¸ªéžè´ªå©ªçš„匹配,用来匹配类名(MyProcesses.Communicators.TCPServer æˆ– MyProcesses.Communicators.UARTPort)。
                    //2.    ([^:] +):匹配冒号之前的部分,即地址(127.0.0.1 æˆ– COM5)。这里使用了[^:] æ¥åŒ¹é…é™¤äº†å†’号之外的任意字符。
                    //3.    (\d +) ï¼šåŒ¹é…ç«¯å£å·ï¼Œç¡®ä¿å®ƒåŒ¹é…ä¸€ä¸ªæˆ–多个数字。
                    var regex = new Regex(@"^\((?<ClassName>[^)]+)\)\[(?<IP>[^]]+)\]\[(?<PORT>[^]]+)\]$");
                    var match = regex.Match(CommunicatorAddress);
                    if (match.Success)
                    {
                        string ClassName = match.Groups[1].Value;   // "TCP"
                        string IP = match.Groups[2].Value;          // "127.0.0.1"
                        string PORT = match.Groups[3].Value;        // "1111"
                        if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
                            break;
                        //利用反射创建实例
                        Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
                        if (type == null)
                        {
                            Debug.WriteLine("Class not found.");
                            return false;
                        }
                        var Communicator = Activator.CreateInstance(type, CommunicatorName) as BaseCommunicator;
                        if (Communicator == null)
                        {
                            Debug.WriteLine("BaseCommunicator not found.");
                            return false;
                        }
                        Communicator.CommunicatorConnections.Add("地址", IP);
                        Communicator.CommunicatorConnections.Add("端口", PORT);
                        Communicator.CommunicatorName = CommunicatorName;
                        if (!Communicator.Connect())
                            LogInfo($"初始化通讯口[{CommunicatorName}]失败,原因是{Communicator.Msg}", LogInfoType.ERROR);
                        else
                            LogInfo($"初始化通讯口[{CommunicatorName}]成功", LogInfoType.PASS);
                        GlobalVar.dicCommunicators.TryAdd(CommunicatorName, Communicator);
                    }
                    else
                    {
                        Debug.WriteLine("No match found.");
                    }
                }
                return true;
            }
            catch { return false; }
        }
        public bool SaveAllCommunicators()
        {
            try
            {
                string strJson = string.Empty;
                GlobalVar.allCommunicatorsConnectionString = new ConcurrentDictionary<string, string>();
                foreach (var item in GlobalVar.dicCommunicators)
                {
                    string ClassName = item.Value.GetType().FullName;// "TCP"
                    string IP = item.Value.CommunicatorConnections["地址"].ToString();//"127.0.0.1"
                    string PORT = item.Value.CommunicatorConnections["端口"].ToString();//"1111"
                    if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
                        break;
                    string CommunicatorConnectionString = $"({ClassName})[{IP}][{PORT}]";
                    GlobalVar.allCommunicatorsConnectionString.TryAdd(item.Key, CommunicatorConnectionString);
                }
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.allCommunicatorsConnectionString, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allCommunicatorsConnectionStringPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch (Exception)
                    { }
                }
                File.WriteAllText(GlobalVar.allCommunicatorsConnectionStringPath, strJson, Encoding.UTF8);
                return true;
            }
            catch { return false; }
        }
        public bool LoadAllProcess(string allProcessConnectionStringPath)
        {
            try
            {
                if (!File.Exists(allProcessConnectionStringPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allProcessConnectionStringPath);
                    SaveAllProcess();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allProcessConnectionStringPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                List<string> lstProcessName = JsonConvert.DeserializeObject<List<string>>(strJson);
                if (lstProcessName == null)
                    return false;
                // ä½¿ç”¨æ–¹å¼
                var sortedKeys = lstProcessName
                    .OrderBy(k => k, new NaturalStringComparer())
                    .ToList();
                GlobalVar.dicProcesses.Clear();
                foreach (var ProcessName in sortedKeys)
                    GlobalVar.dicProcesses.TryAdd(ProcessName
                        , new ProcessRunBll(ProcessName, GlobalVar.dicCameras, GlobalVar.dicCommunicators));
                return true;
            }
            catch { return false; }
        }
        public bool SaveAllProcess()
        {
            try
            {
                string strJson = string.Empty;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(GlobalVar.dicProcesses.Keys.ToList(), settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessConnectionStringPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allProcessConnectionStringPath, strJson, Encoding.UTF8);
                foreach (var process in GlobalVar.dicProcesses.Values)
                {
                    if (!process.Save(out string msg))
                        LogInfo($"流程[{process.Name}]保存失败,原因:{msg}", LogInfoType.NOSHOW);
                }
                try
                {
                    string json = JsonConvert.SerializeObject(GlobalVar.ControlStates, settings);
                    File.WriteAllText(GlobalVar.allRunSettingStringPath, json);
                    LogInfo($"流程运行设置保存成功", LogInfoType.INFO);
                }
                catch { }
                return true;
            }
            catch { return false; }
        }
        public bool LoadAllProcessVars(string allProcessVarsPath)
        {
            try
            {
                if (!File.Exists(allProcessVarsPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allProcessVarsPath);
                    SaveAllProcessVars();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allProcessVarsPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                IProcess.dicGlobalVars.Clear();
                IProcess.dicGlobalVars = JsonConvert.DeserializeObject<ConcurrentDictionary<string, object>>(strJson);
                if (IProcess.dicGlobalVars == null)
                {
                    IProcess.dicGlobalVars = new ConcurrentDictionary<string, object>();
                    return false;
                }
                return true;
            }
            catch { return false; }
        }
        public bool SaveAllProcessVars()
        {
            try
            {
                string strJson = string.Empty;
                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    // è‡ªå®šä¹‰ç¼©è¿›ï¼ˆ4空格)
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new CamelCaseNamingStrategy()
                    }
                };
                strJson = JsonConvert.SerializeObject(IProcess.dicGlobalVars, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessVarsPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allProcessVarsPath, strJson, Encoding.UTF8);
                LogInfo($"全局变量保存成功", LogInfoType.INFO);
                strJson = JsonConvert.SerializeObject(GlobalVar.dicLayout, settings);
                //判断文件夹是否存在,防呆输入为文件名称
                directoryPath = Path.GetDirectoryName(GlobalVar.allLayoutPath);
                if (!Directory.Exists(directoryPath))
                {
                    try
                    {
                        Directory.CreateDirectory(directoryPath);
                    }
                    catch { }
                }
                File.WriteAllText(GlobalVar.allLayoutPath, strJson, Encoding.UTF8);
                LogInfo($"全局布局保存成功", LogInfoType.INFO);
                return true;
            }
            catch { return false; }
        }
        public bool LoadAllLayout(string allLayoutPath)
        {
            try
            {
                if (!File.Exists(allLayoutPath))
                {
                    Debug.WriteLine("文件不存在创建空文件");
                    // èŽ·å–ä¸å¸¦æ–‡ä»¶åçš„ç›®å½•è·¯å¾„
                    string directoryPath = Path.GetDirectoryName(allLayoutPath);
                    SaveAllLayout();
                    return true;
                }
                string strJson = string.Empty;
                using (StreamReader streamReader = new StreamReader(allLayoutPath, Encoding.UTF8))
                {
                    strJson = streamReader.ReadToEnd();
                    streamReader.Close();
                }
                GlobalVar.dicLayout.Clear();
                GlobalVar.dicLayout = JsonConvert.DeserializeObject<ConcurrentDictionary<int, Forms.Pages.SettingPage.Layout>>(strJson);
                if (GlobalVar.dicLayout == null)
                {
                    GlobalVar.dicLayout = new ConcurrentDictionary<int, Forms.Pages.SettingPage.Layout>();
                    return false;
                }
                return true;
            }
            catch { return false; }
        }
    }
}
LB_SmartVision/VisionForm.resx
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1080 @@
<?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>
  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  <data name="theme_VisionForm.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
        vAAADrwBlbxySQAAA+JJREFUWEftVkuIHGUQbt34iMEoq2S2q3p3yTJsuqpnJ+L6WBRdwaigohfFgEou
        BkVBUPCBCEG8BXNQ48GLeImCehIJxMsqhsSZruod46K4HtSIGjU+4iOr0c1I9fSsM3/PLNtCPO0H36m/
        evz/X11VnreKVRTAHPOZumkY6lFwqURws3BwZ8ywTQnuiCP/+iTCzY1qaUPzdm/Atf3PaHre6XPsjyQM
        2xLGV4XwIyX4QRj+UMK/lPFvJTyhBMeV8IgQvmRJuH4Ko+l5p9UjGBbCJ5RxTgj+VMZmXxKcSAjekHE/
        NNs5DgaTKLinEQYVO4Trf1mkV81wixLUslPmA3bzF2XcKeP+hWY/u3n0fCXcrQwLyjAvjNsb1dI6N05P
        mFAIHlHG73sEypPgGwnhfpn0zzH7jzddcK4Q7kqfKNMI4a9K+MwBDgbdeF04MBWsFYYdQvhbLlBvfhKT
        f+vMtLfG7C0JJXxKGY67WnvCmPAFGRs7z42boul5AzHBfdK6TjdQtzPGk8oos5F/5Y7sfVvPhg+lp+1h
        0yIsxARPmtaN78WEl8eEX+SNclxUhne0glUrNrN9zfMGlPAuZTzaQ99FYfwuDv3ruoLvq5bWaQSvZCfL
        GXUYLwrj240Qxtu2lkSN4FpdWfKZH9jb9RQ1Cq62f9sVOlxUxn3KQXnJ0PO8QxU/jBm1h74v7ZniEG9K
        Hdg/quzvXO709k0Y3u08ucGqWgheX862H4XgxbR47SqU8D1X0EXC2VmGizqDz0xPr0kYH9eO360gNe0b
        jWppozB+1kOQEb5MCLa0C64NoeGrhOGrvH6lhK81GiIvnggmrDLzgvTkvwvDA+5wsU4nhG/m9AUoBD/F
        HFzWN4H0XQn2vF8eXN8Z3FAPYasl59oUYjuB+sTImDB+nhfgYQ39STf4fmu1DHtz+oIUgiM1KkWtwcFw
        sOujVT3hrnaL7UQc+hcL5W+sKIXhw0OVjaW0iwnBc47gqIQ45QY32PKRzv8eTguRYM9SS5YouEEZjv37
        EffbzbjBDdZyxZYQ12EB2qS0bWrJqRVazPDWkojwZbuZrsgZtDJ0iY1g12khEtTicMTvclwn2CKE32YJ
        7G5PORfZ1HtMCH7MOV4BrQ3XCe92+4onk5Nn2PolDAvWXnuOzAwzo6Nnx4Q3SrojwqfKeMxWMpsXWVs+
        2WrfKRdbW1W6Hf0shM/33Y7my4PrleFZIfhAaWjU/e5ivlw+y3S2FySMtynjvcrwsFiLJv/RhPBB2ws1
        hK2WcBLBFf1qawlplwvxaQlxe786OOU4PBWsjSO85mBlQ8n99r/BisSdAas4FfgHpdEUZpwUX7sAAAAA
        SUVORK5CYII=
</value>
  </data>
  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
    <value>
        AAABAA0AICAQAAEABADoAgAA1gAAABAQEAABAAQAKAEAAL4DAAAwMAAAAQAIAKgOAADmBAAAICAAAAEA
        CACoCAAAjhMAABAQAAABAAgAaAUAADYcAAAAAAAAAQAgAC0RAACeIQAAQEAAAAEAIAAoQgAAyzIAADAw
        AAABACAAqCUAAPN0AAAoKAAAAQAgAGgaAACbmgAAICAAAAEAIACoEAAAA7UAABgYAAABACAAiAkAAKvF
        AAAUFAAAAQAgALgGAAAzzwAAEBAAAAEAIABoBAAA69UAACgAAAAgAAAAQAAAAAEABAAAAAAAgAIAAAAA
        AAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD/
        /wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAIkAAAAAAAAAAAAAAAAAAACXAAAA
        AAiXk5k5GXmAAAAJOAAAAAB5OZGTkZk5kAAAeZgAAAAJGZOTmTkZk5kAAJGXAAAACTk5kZOZk5OTAAiT
        mQAAAAkZk5ORk5kZmXAHmZGAAAAJmTmRmZOTk5FwB5OTkAAABzmTk5OZGZOZMAmZGZcAAACZOZGZGTk5
        k5AHk5OZAAAAeRk5OTmRkZmQCZOZk5AAAAmZOZGZOTmTcAeTk5k5AAAAOZOTkZmTmZAImZGTmXAAAHmT
        mZOTk5GAAHk5k5OXAAAHk5OZGZOZAAB5mTmRmXAAAJmRk5ORlwAABxk5OTmXAAAHk5mTmZAAAACZOZGZ
        GXAAAJmTk5MAAAAAB5OZOTmZAACDkZmXAAAAAACZk5kZOXAACJmXgAAAAAAAB5k5ORk5gACDkAAAAAAA
        AAAJOZmZOZcAAAAAAAAAAAAAAAd5OZOZcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////
        ////////+/////P////z/gAH4/wAB8P4AAPD+AADg/gAAYH4AAGB+AABgPwAAYD8AAGAfgABgD8AAYAf
        AAHAD4ADwAfAA+AD4AfwAfAP+ADwD/wAeB/+ABx//4AP///gB////////////////////////////ygA
        AAAQAAAAIAAAAAEABAAAAAAAwAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAA
        gACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAHAACZeXlwAJcACDmRmTkAmQAImRk5OQg5cAA5OZkZiJlwAHmZOTmAGZkABzkZmQB5OXAAmZ
        OXAAk5lwADkZAAAJmTkAiZgAAAB5mZgAAAAAAACHeAAAAAAAAAAAAAAAAAAAAAAAAAD//wAA//8AAP//
        AADeAwAAnAEAAJwBAAAOAAAADgAAAIcBAACDgQAAwcMAAODDAADwPwAA/D8AAP//AAD//wAAKAAAADAA
        AABgAAAAAQAIAAAAAACACgAAAAAAAAAAAAAAAQAAAAAAAAAAAAAbKswAHCvMAB4szAAgL80AIjHNACUz
        zgAmNc4AKDbPACo4zwAqONAALDrQAC480AAwPtAAMkDRADRB0QA3RNIAOUbTADtI1AA/TNQAQE3UAENQ
        1QBFUdUASVXWAE1Y1wBPWtgAUFvYAFFd2ABVYNkAWGPZAFpl2gBeadsAYGrbAGNu3ABkbtwAZ3HdAGhy
        3QBrdN0AbHbeAG943wBxet8AcnzfAHR93wB0feAAd4DgAHmC4QB7hOEAfYbhAIGK4gCDjOMAho7kAImQ
        5ACMk+UAALB5AADPjwAA8KYAEf+0ADH/vgBR/8gAcf/TAJH/3ACx/+UA0f/wAP///wAAAAAAAC8OAABQ
        GAAAcCIAAJAsAACwNgAAz0AAAPBKABH/WwAx/3EAUf+HAHH/nQCR/7IAsf/JANH/3wD///8AAAAAAAIv
        AAAEUAAABnAAAAiQAAAKsAAAC88AAA7wAAAg/xIAPf8xAFv/UQB5/3EAmP+RALX/sQDU/9EA////AAAA
        AAAULwAAIlAAADBwAAA9kAAATLAAAFnPAABn8AAAeP8RAIr/MQCc/1EArv9xAMD/kQDS/7EA5P/RAP//
        /wAAAAAAJi8AAEBQAABacAAAdJAAAI6wAACpzwAAwvAAANH/EQDY/zEA3v9RAOP/cQDp/5EA7/+xAPb/
        0QD///8AAAAAAC8mAABQQQAAcFsAAJB0AACwjgAAz6kAAPDDAAD/0hEA/9gxAP/dUQD/5HEA/+qRAP/w
        sQD/9tEA////AAAAAAAvFAAAUCIAAHAwAACQPgAAsE0AAM9bAADwaQAA/3kRAP+KMQD/nVEA/69xAP/B
        kQD/0rEA/+XRAP///wAAAAAALwMAAFAEAABwBgAAkAkAALAKAADPDAAA8A4AAP8gEgD/PjEA/1xRAP96
        cQD/l5EA/7axAP/U0QD///8AAAAAAC8ADgBQABcAcAAhAJAAKwCwADYAzwBAAPAASQD/EVoA/zFwAP9R
        hgD/cZwA/5GyAP+xyAD/0d8A////AAAAAAAvACAAUAA2AHAATACQAGIAsAB4AM8AjgDwAKQA/xGzAP8x
        vgD/UccA/3HRAP+R3AD/seUA/9HwAP///wAAAAAALAAvAEsAUABpAHAAhwCQAKUAsADEAM8A4QDwAPAR
        /wDyMf8A9FH/APZx/wD3kf8A+bH/APvR/wD///8AAAAAABsALwAtAFAAPwBwAFIAkABjALAAdgDPAIgA
        8ACZEf8ApjH/ALRR/wDCcf8Az5H/ANyx/wDr0f8A////AAAAAAAIAC8ADgBQABUAcAAbAJAAIQCwACYA
        zwAsAPAAPhH/AFgx/wBxUf8AjHH/AKaR/wC/sf8A2tH/AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADImAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAKwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAtBBkAAAAAAAAAAAAAAAAAAAAAAAAAMisnIyMjJistMgAAAAAAAAAAAAAAAAAAADQEAS4A
        AAAAAAAAAAAAAAAAAC0VCgQBAQEBAQEBAQEBAQEEBAYkAAAAAAAAAAAAAAoBAQAAAAAAAAAAAAAAAAAj
        CgEBAQEBAQEBAQEBAQEBAQEBAQEEAAAAAAAAAAAAFwEBBAAAAAAAAAAAAAAAABkBAQEBAQEBAQEBAQEB
        AQEBAQEBAQEBDgAAAAAAAAAyBAEBAQAAAAAAAAAAAAAALQQBAQEBAQEBAQEBAQEBAQEBAQEBAQEBASMA
        AAAAAAASAQEBATAAAAAAAAAAAAAAFQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQoAAAAAAAAEAQEBARwA
        AAAAAAAAAAAADgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEtAAAAABwBAQEBAQwAAAAAAAAAAAAAEAEB
        AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEVAAAAAAwBAQEBAQE0AAAAAAAAAAAAFwEBAQEBAQEBAQEBAQEB
        AQEBAQEBAQEBAQEGAAAAAAQBAQEBAQEVAAAAAAAAAAAALQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEC
        AAAAAAEBAQEBAQEEAAAAAAAAAAAAAAgBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBLQAALAEBAQEBAQEB
        EgAAAAAAAAAAABwBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBIwAAJgEBAQEBAQEBASYAAAAAAAAAAAAG
        AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBHwAAJgEBAQEBAQEBAQYAAAAAAAAAAAAeAQEBAQEBAQEBAQEB
        AQEBAQEBAQEBAQEBHwAALQEBAQEBAQEBAQEQAAAAAAAAAAAACwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
        IwAAAAEBAQEBAQEBAQECGQAAAAAAAAAAMQQBAQEBAQEBAQEBAQEBAQEBAQEBAQEBMAAAAAQBAQEBAQEB
        AgEBASEAAAAAAAAAABoBAQEBAQEBAQEBAQEBAQEBAQEBAQECAAAAAA4BAQEBAQEBAQECAQQrAAAAAAAA
        AAAOAQEBAQEBAQEBAQEBAQEBAQEBAQEKAAAAAB8BAQEBAQEBAgEBAQEEMAAAAAAAAAAABgEBAQEBAQEB
        AQEBAQEBAQEBAQEYAAAAAAAEAQEBAQEBAQECAQEBBjIAAAAAAAAAKwIBAQEBAQEBAQEBAQEBAQEBAQMA
        AAAAAAAWAQEBAQEBAgEBAQEBAQYyAAAAAAAAAB4BAQEBAQEBAQEBAQEBAQEBARAAAAAAAAAABAEBAQEB
        AQECAQEBAQEGMgAAAAAAAAAVAQEBAQEBAQEBAQEBAQEBAzIAAAAAAAAAHQEBAQEBAgEBAQEBAgEBBC4A
        AAAAAAAAEAEBAQEBAQEBAQEBAQEBFgAAAAAAAAAAAA8BAQEBAQECAQEBAQECAQQnAAAAAAAAAAsBAQEB
        AQEBAQEBAQEIAAAAAAAAAAAAAAAIAQEBAgEBAQEBAgEBAQEEIAAAAAAAAAAIAQEBAQEBAQEBAQQzAAAA
        AAAAAAAAAAAABQEBAQECAQEBAQECAQEBAhoAAAAAAAAABQEBAQEBAQEBAykAAAAAAAAAAAAAAAAAAAgB
        AgEBAQEBAgEBAQEBAQETAAAAAAAAMAQBAQEBAQEEJwAAAAAAAAAAAAAAAAAAAAAOAQECAQEBAQECAQEB
        AQEBDgAAAAAAAC0EAQEBAQYwAAAAAAAAAAAAAAAAAAAAAAAAGgMBAQEBAgEBAQEBAQEBAQgyAAAAAAAp
        AwEBEQAAAAAAAAAAAAAAAAAAAAAAAAAAADMPAQEBAQECAQEBAQEBAQEEIwAAAAAAJgokAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAALhADAgEBAQEBAQEBAgECAhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAHAwDAQEBAQEBAQECAQIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALh4X
        EQ8ODxIWHSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////AAD/P/////8AAP5/
        /////wAA/H//8AP/AAD4f/4AAB8AAPj/+AAAHwAA8P/wAAAPAADg/+AAAAcAAOB/4AAABwAA4H/gAAAD
        AADAf+AAAAMAAMA/4AAAAwAAwD/gAAADAADAP/AAAAEAAIAf8AAAAQAAgA/4AAABAACAD/gAAAEAAIAH
        /AAAAQAAwAP8AAABAADAAf4AAAMAAMAA/wAAAwAAwAB/gAADAADgAD+AAAcAAOAAH8AABwAA8AAP4AAH
        AADwAAfwAA8AAPgAA/gAHwAA/AAB/AAfAAD+AAD+AD8AAP8AAH4AfwAA/4AAPwD/AAD/wAAPg/8AAP/g
        AAfH/wAA//gAA///AAD//wAB//8AAP//4AP//wAA////////AAD///////8AAP///////wAA////////
        AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAgAAAAAAIAEAAAAAAAAAAAAAAAB
        AAAAAAAAAAAAABsqzAAcK8wAHizMACAvzQAhMM0AJDLOACY0zgAoNs8AKDbQACo40AAtOtAALjzQADA+
        0QAzQdIANULRADdE0gA6R9MAO0jUAD1K1ABBTtQARlLVAElV1wBMWNcAT1rYAFBb2ABRXdgAWGPZAFpl
        2gBeaNoAZG7cAGlz3QBpdN4Ab3jfAHF63wB1fuAAeoLgAHuE4QB8heIAgYniAIqR5AAx8f8AUfP/AHH1
        /wCR9/8Asfn/ANH7/wD///8AAAAAAAAvIQAAUDcAAHBMAACQYwAAsHkAAM+PAADwpgAR/7QAMf++AFH/
        yABx/9MAkf/cALH/5QDR//AA////AAAAAAAALw4AAFAYAABwIgAAkCwAALA2AADPQAAA8EoAEf9bADH/
        cQBR/4cAcf+dAJH/sgCx/8kA0f/fAP///wAAAAAAAi8AAARQAAAGcAAACJAAAAqwAAALzwAADvAAACD/
        EgA9/zEAW/9RAHn/cQCY/5EAtf+xANT/0QD///8AAAAAABQvAAAiUAAAMHAAAD2QAABMsAAAWc8AAGfw
        AAB4/xEAiv8xAJz/UQCu/3EAwP+RANL/sQDk/9EA////AAAAAAAmLwAAQFAAAFpwAAB0kAAAjrAAAKnP
        AADC8AAA0f8RANj/MQDe/1EA4/9xAOn/kQDv/7EA9v/RAP///wAAAAAALyYAAFBBAABwWwAAkHQAALCO
        AADPqQAA8MMAAP/SEQD/2DEA/91RAP/kcQD/6pEA//CxAP/20QD///8AAAAAAC8UAABQIgAAcDAAAJA+
        AACwTQAAz1sAAPBpAAD/eREA/4oxAP+dUQD/r3EA/8GRAP/SsQD/5dEA////AAAAAAAvAwAAUAQAAHAG
        AACQCQAAsAoAAM8MAADwDgAA/yASAP8+MQD/XFEA/3pxAP+XkQD/trEA/9TRAP///wAAAAAALwAOAFAA
        FwBwACEAkAArALAANgDPAEAA8ABJAP8RWgD/MXAA/1GGAP9xnAD/kbIA/7HIAP/R3wD///8AAAAAAC8A
        IABQADYAcABMAJAAYgCwAHgAzwCOAPAApAD/EbMA/zG+AP9RxwD/cdEA/5HcAP+x5QD/0fAA////AAAA
        AAAsAC8ASwBQAGkAcACHAJAApQCwAMQAzwDhAPAA8BH/APIx/wD0Uf8A9nH/APeR/wD5sf8A+9H/AP//
        /wAAAAAAGwAvAC0AUAA/AHAAUgCQAGMAsAB2AM8AiADwAJkR/wCmMf8AtFH/AMJx/wDPkf8A3LH/AOvR
        /wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+Ef8AWDH/AHFR/wCMcf8AppH/AL+x
        /wDa0f8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJhQAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIAAAAAAAAAAAACASCQQEAQEBAQIEBgkmAAAAAAAADQEm
        AAAAAAAAAAAKAQEBAQEBAQEBAQEBAQkAAAAAAB0BASEAAAAAAAAADQEBAQEBAQEBAQEBAQEBARYAAAAA
        CQEBGAAAAAAAAAADAQEBAQEBAQEBAQEBAQEBBAAAACYBAQELAAAAAAAAAAQBAQEBAQEBAQEBAQEBAQEB
        IAAAFwEBAQEnAAAAAAAACwIBAQEBAQEBAQEBAQEBAQEUAAAQAQEBAQ4AAAAAAAAcAQEBAQEBAQEBAQEB
        AQEBAQwAAAsBAQEBASAAAAAAAAAGAQEBAQEBAQEBAQEBAQEBCQAACwEBAQEBBgAAAAAAAB4BAQEBAQEB
        AQEBAQEBAQEJAAAQAQEBAQEBDgAAAAAAAA4BAQEBAQEBAQEBAQEBAQ0AABkBAQEBAQEBFgAAAAAAAAQB
        AQEBAQEBAQEBAQECFQAAJwEBAQEBAQEBGgAAAAAAHgIBAQEBAQEBAQEBAQEjAAAACgEBAQEBAQECHAAA
        AAAAFgEBAQEBAQEBAQEBBgAAAAAgAQEBAQEBAQECHAAAAAAAEAEBAQEBAQEBAQEcAAAAAAAPAQEBAQEB
        AQECGgAAAAAACwEBAQEBAQEBCwAAAAAAAAAHAQEBAQEBAQEBFgAAAAAABgEBAQEBAQUAAAAAAAAAAAAG
        AQEBAQEBAQEBEgAAAAAoBgEBAQEEJAAAAAAAAAAAAAALAQEBAQEBAQEBDQAAAAAnBAEBBicAAAAAAAAA
        AAAAAAAWAwEBAQEBAQEBCScAAAAkBRIAAAAAAAAAAAAAAAAAAAAAFAQBAQECAQEBAx4AAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAB8TCgQDAwMFDCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAD/////////////////////+/////P////z/gAH4/wAB8P4AAPD+AADg/gAAYH4
        AAGB+AABgPwAAYD8AAGAfgABgD8AAYAfAAHAD4ADwAfAA+AD4AfwAfAP+ADwD/wAeB/+ABx//4AP///g
        B////////////////////////////ygAAAAQAAAAIAAAAAEACAAAAAAAQAEAAAAAAAAAAAAAAAEAAAAA
        AAAAAAAAGyrMAB4szAAiMM0AJTPOACY0zgApN9AAKznQAC070AAvPdAANULRADtI0wA8SdMAQEzUAEhU
        1wBPWtgAVmHZAGRu3ABpct0AbHbeAHeA4AB4geAAf4fiAH+I4gCBieMAhIzjAIeP5ACIkOQAkc//ALHd
        /wDR6/8A////AAAAAAAALC8AAEtQAABocAAAhpAAAKWwAADDzwAA4fAAEe//ADHx/wBR8/8AcfX/AJH3
        /wCx+f8A0fv/AP///wAAAAAAAC8hAABQNwAAcEwAAJBjAACweQAAz48AAPCmABH/tAAx/74AUf/IAHH/
        0wCR/9wAsf/lANH/8AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sAMf9xAFH/
        hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAAIP8SAD3/
        MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAAZ/AAAHj/
        EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAAqc8AAMLw
        AADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAAsI4AAM+p
        AADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAAkD4AALBN
        AADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAAcAYAAJAJ
        AACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4AUAAXAHAA
        IQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAALwAgAFAA
        NgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8AAAAAACwA
        LwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A////AAAA
        AAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A69H/AP//
        /wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8Av7H/ANrR
        /wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA
        ABEKBgQEBggAAAAMDgAAABUBAQEBAQEBCgAAAgYAAAAUAQEBAQEBAQIAGgEBEgAAAAQBAQEBAQEBGBsB
        AQQAAAASAQEBAQEBARgAAgEBCQAAAAsBAQEBAQIAAA0BAQEKAAAABwEBAQELAAAABAEBAQoAAAAEAQED
        AAAAAAAFAQEBCAAAGwMEGQAAAAAAAA8DAQEEFgAAAAAAAAAAAAAAABsTEhcAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AAD//wAA//8AAN4DAACcAQAAnAEAAA4AAAAOAAAAhwEAAIOB
        AADBwwAA4MMAAPA/AAD8PwAA//8AAP//AACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAAAFxyqGYA
        ABD0SURBVHja7d0/etzGGcfxAbhUytCVH4mFmcoWXXj1SKrNnMCbE4Q+gekThDlB6BOEPoHlE4SuJT+i
        i1BKFbqg9KQyWUpcAsHsCuZqxSUGwAzmz/v9FJZk0xS4u/PDzDt/kCkAYmW+LwCAPwQAIBgBAAhGAACC
        EQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACC
        EQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACCEQCAYAQAIBgBAAhGAACC
        EQAJeb59bzzNsg39+7xQO/W/LzM1rv65sfz1mcq+vOn7FEXxS5Zn5x/+l+w8K9Xx9fctT8ssO9W/H41G
        xw9++fVcISoEQGSefr65k5XlVlZmW3XDzlRZ/Zr/0fe1aYVSv1bXc1qHRR0SBESYCIBAPf/0462rPB9n
        Kh9XjWinVNlWrtQnvq+rn+Ki+jmOqw/dcVlkp+WaOn7877Mj31clGQEQiNmd/aq6o+eqauxqHH9jN6eH
        HHmWH5dVj2EtL48enLw67v9dYYIA8ESP16+KbEc3+OpN+Mr39YRF9xTyo2o8cUQguEUADOT5F59sXF1e
        Tqqx+47KikkoY/Y4FBdFlk8YLthHADg0G8evre1UL/OEu3xXVW+gVLuPXrx+4vtKUkQAWFbf6avf7q6a
        ZoMZXRsY5dkuQwB3CABLnt2/O1FZvsud3o5SqR/X1ke7TB26RQD0oLv4xdraXvVx3WVMb09ZqG8fvTw7
        8H0dEhAAHczv9tkeXXzbKPYNjQAwNBvbv5nulrnakzRHP5TZeP8Pd3bo8g+LAGgw6+bno12VFXt08x0p
        1fcPX5zt+r4MiQiAFd41/P3qFfqr72tJWanKrx+dvDr0fR1SEQBLaPhDKS5yle0MOcX38/3NQ/1rXkz3
        H/znf6e+X4EQEADv6DF+cXm5X70k3/i+ltT5GO/PGv/voV5cqDI/yO+MDqTXHMQHwKzhv53uMcYfiIfx
        /vuNf9Fsd+Ke5CGI6AB4tn1vt/oA7FPVH4aP8f7qxn9N90jUWr4ncfpRZADMduIpdcA8/lCGH+9rJo3/
        PVXvpBoW7EkaFogKAMb5w/M1v9+68V9fsahhgZgA0Kv3skwdMs4fkKf5/e6Nf/HSy5/Wrq52U58tSD4A
        5ltyRwds0hmWr/l9G43/WtUbKPL9lPclJB0Azz7b3MvyYp+7/pD8jPe1+fut/mH7+856A+vrkxRrA0kG
        wHxP/vSQu/6wZuP9spj46DbrGZ1MZf90+NMleTBJcgHAWN8TjxV0943/vR/0u3x9fT+V3kBSAfDz9r0D
        KvwelOrvD1+c7fv4q4dt/HMpnVSURADoQt80y5/kef6F72uRxW+32EfjD+VntyX6AKDL74d+AtBIlRNf
        d0G/jX9R+d3Dk1d7vq+iq6gD4Of7m3rX3t98X4c0vg/vmId+/oPv16EW8/mFUQYAVX6PPB/eoZdxF6o8
        Cq3HF2tdILoAYLzvj+/DOkNt/Nf8rYHoKqoACP8DkCr/Ba943vu49hJEEwAU+/zwXezT4mn812I56iyK
        AAin4iuL72Kfpus908vpcZRnNnhcH2Eq+ACg8XsSwEm9s8b/5u1R1PWeAF7H2wQdAKzs8ySAO1cSjb8W
        cAgEGwB2t3XCTBgFrKQafy3QEAgyAGj8PoQzhZXs+x9gCAQXAMm++QHzuY13WfLvf2AhEFQAsLR3eCFU
        +mvJN/5aADWWWjABQLXfg4DuRq5O8wlVKOsEgggAGr8HAd2FpL7/IYSA9wB4+vnmTl6qf/m+DklC+ODV
        pDb+Of+FV68BEOMSz7gVF0WWT0J5Ag7vv1aFwFUx9lWA9RYA84d0vD2V/eYPyf/dZhGN/5rPQqyXAEhy
        oUfAQqr0a7NHsK/lxzT+a/pQkUcnZ5Oh/14vASBmuicAwTV+wn81D4XZwQNA2nSPVwFN82k0/mZlWfxl
        yHMXBg2A+bgvez7k3ylWYI1fo+dnYtii4GABQNFvOCFN89Vo/Ob0sO3xy9fjIf6uwQLg2fbmEw7xdC/E
        xs+wr4OB6gGDBAAfgCH4P7fvJrIX+vRTZOrPrtdsOA8Axv1DCGuOv8Z738/sPMb10djlDI7zAHj62d1j
        qr4uhdz4WejTn9snDzkNALb3uhXaHH8t6oM8A+RyKOAsAOj+uRV042eu3yqXQwFnAUDX351QG7/GdJ8j
        jmYFnAQAVX+HSvV9fme0F2Tj5xRnp/Kr6Z9sLxCyHgAs+HEowNV9Nab73CtV+dOjk1c7Nr+n9QCgC+hI
        wI2fQ12GY3uvgNUA4IPgSMCNn+m+YemC4OOTsy1b389qAFTdwKOqG/jl4K9K0tzOA/dBxd8TiwVBawHA
        GNC+ENf1L2Kmx5fiIl+/s2WjEGwtAJ5ub56y8MOe0Bs/tR7PLPUCrAQAd3+7Qm/8vN8hsNMLsBIA3P3t
        Cb3xU+gNiIVeQO8A4G5gT+iNn4p/aPr3AnoHAHd/O4Jv/FT8w9SzF9ArALj72xF649c40SlUxcXDk9cb
        Xf/vvgHAvH9PMTR+tnWHrc9nqHMAUAzqL4bG/+z+3UmW5T/4vg6s1ucQ0c4BwDxwPzE0fop+8eh6aEin
        AJjv+Jv+5vuHjlUUjZ+iX1w67hfpFADs9+8uhsavUfSLT74++qjtlGCnAGDqr5toGj8BH6Uun6/WAcBZ
        f92Uhfr20cuzA9/X0YTibry6FANbBwDFvw4C3s+/iNOc4tf22LD2AbB995wPSAuRNH6NdR3xa9vTbBUA
        zAm3FFHjZ7FPGtoOA1oFAN3/FiJq/Iz709JmGNAqAKj+mwn53P5ljPvT02YYYBwAVP/NxNT4Ncb96SmV
        +vHRydnE5GuNA4AxYrMhnuZqE+9puh6enBm1beMA4E7RJMyn9K7CuD9tps8PMAoA1v43iavx8/ReCcyO
        kzcKAKb/bmf7aS2usc4/faaPETMKAMaKq8Wyvr/GKU5ymNQBzHoAjP9XCPepPTd5/unHW8VafsyUnwwm
        ZwSY9QC2N0vfP0xwIlroUyPIhTE4MLQxAJj//1Bsc/0awzh5TNYDNAYAY8b3xTbXrxHiMpnsC2gMAO4c
        i+Ka7qvxEE+5mgqBJj0Axo3vxDbdpxHgsjUVAhsDgA1Ac7Gc6LOIrj+ablrNQwBmAKKs+Gt0/dE0E3Br
        AHAHibPir9H1x0zDzevWAGDDSHGRXxXjNmeshWC+4Gf0X9/XAf+algTfGgDSj4fu+rQV3yjcotY0FXhr
        AIjuRvZ87LIvrNvAstumAgmAG7Q5USUkHO+Fm3QOAIldyRhX+tU4tBU3ue2QUAJgSa7KB7Gt9NMo2GKV
        22pZBMCCGBf71JjzxyoEgAHTE1RCROEPtyEAGhUX+fqdrRjH/RT+0KRzAEh5DmCMm3xqUmdqYK5HAEjY
        BxDXsV6LWPEHEwTACjFP+WlM+8EEAbBCrFN+Ghu1YIoi4E0iXepbS/q9gVUEwPIL0vIZ6qFh0Q/aIACW
        xNz111J9X+AGAfCeeKv+Gnd/tEUA1C9E5FV/LbX3BO71mAW4d1B9yTe+f4AhXogYUPlHF5wHoOLd47+I
        eX90QQBEerbfIlb9oavOAZBMwSnyOX8tnTDGkHodCppCAKRQ+NOkbMyCXb0CYL7VdPqb7x+i5wvwdfUC
        HPq+jj7Y74/ubp/2TvrJQDEf8rGIqT901ufJQFrMH77Yp/00in/oo/ezAZ9tbz6pvugr3z9I6x88kbt/
        amsxMKzeTweOtfp821HIMeHpzOjjtilArfnx4DHOBET6NN9lrPxDH3oG7PHJ2dZtX9MYADGOQVO5+9P9
        Rx8mq18bA0CLag46kbu/RvcfvRgsgDMKgJgKgSlU/rUYe14Ii0lbMOsBRFIITKXyr0l/NDv6y9dHHzWt
        gDUKgFgKgTGf778spl4XwmNSANSMAkALfUWg6Q8cC8b/6MWwFmYcAKHfkWJ+sOcyxv/oy3QPjHkABD4m
        NRnvxOLZ/buTLMt/8H0diJfpVLhxAAS9KCWhqT8tlqIrwtRmOGwcAFqo49JUpv5qoQ+3EDrzk69bBUCI
        K9NSK/5pMe/AhH9tZsNaBUCYw4C4z/m/Sag9LcSguHh48nrD9KtbBYAW2ocz9qf83CT0KVcErGU9rHUA
        hDQMSLH7rxEA6KrtYrjWARDWMCC97r9GAKCbdt1/rXUAaKEMA1Kr/tcIAHTSYTq8UwCEsSiofdrFggBA
        F132wnQKgBCOC0/hUV+rEABoq2s9rFMAaL6fU5fS2v9lBABa6/j0q84B4HuLcIrTfzUWAqGtrsfgdQ4A
        7elnd4/zPP/Cxw/cdNppzFgKjDb6DId7NSJfj6xK6eSfm7AZCG30mQ3rfRf1MyWY5vx/zffwCvEoiuKX
        xy9fj7v+/70DwEcvIIUHfjahEAgTfduClXH00L2AVBcALaIOgCY2lsJbCYChewEpnf6zCo8ERxMbPWFr
        lfQhewEpzwAsiuqBLBiUrY1w1hrSUHesVHcA3oTZAKxiqw5m9U46xLqA1KcAF82XXL89pReARTZvgnYD
        YIDpK0kBoIWx8QohsVkEtz6Wdl29lhYAGkuDUbP9+bceAPOHWuTHzrqtHTc9xMz5a4po2N4D46Sa7rR4
        JTAANB4WAhcrYJ1NpzkrCAoNAI21AZIVF/n6nS3b61+cBYC7swPT3gfQhBCQydWTr50uqHFxgrDEIuAy
        QkAWl6dfOV9RZ3soQADMzadciycUBlPnputfcx4AtocCBMA1PTtwtbZ2yBRhulx1/WuDrKm3OyuQ7mnA
        Xc1f32KP3kBiBnjq9WCbamwuZpGyGaiNeW9gdMAW4jTo5b6j9dHY9a7XwRqSzXXtKR8I2peuDWRluc+w
        IG5DfcYHvZPa2ivgelyUAoIgXkOeeDV4V9rK5hbBi4Hami0jzke6RjChRhCBAcb9i7yMpfs+VISZgPb0
        EOzq8rIKgWxCnSBMfQ/47MJLAOgP4/TN26Pu6wOYCejj/TAodugZhMDtfP8q3qrpfYuCFALtmdVmCrVT
        ZuUONQMfqsavsh0fn2ev02nzRULlUZcQSPnZgL7NCohXapxlalyUxdjX05+k8HnKtff59K4zAz7GS5K9
        m1XYyspsS/cUyqLcIBhW0/P4mSpP53/KzrNSze7uZanOy7X570dlee67F+s9ALSum1u6PhAR9uhZhulo
        tJUVxUam8lkg64CY/ZpASOiC8+KfqwA8Wvxzkavf/zwajY5jO64+iADQuoQAw4C46F7E4p913WHV19Yh
        0kXVSE+rX05Xfu+Fu/Ci0XR6Ku2GEkwAaG1DgGEA0E9QAaC1DQFmA4DuggsArVUIDLxyCkhJkAGgmYeA
        nwUUQAqCDQDNOATYGwB0EnQAaGYhQC8A6CL4ANCMzr+jFwC0FkUAaM3LhqtewFUxljaPC/QRTQBos1Vn
        Wf5k5eoyZgSAVqIKAG2+lXV6uGpPu8+NFUBsoguA2qqThm0+Ox1IXbQBoM0fmKkOP6gLUBAEjEQdAJou
        Dk6L8nC5LsBQAGgWfQBos9OF3k4PFs8ZHOpcdSBmSQRAbXlI4PKhikAKkgoA7YPn5VEPAFZKLgBq8+cP
        FPu6N8CDRICbJRsA2nVvoBz7OnUVCFnSAVDTvYEyV3sUBYH3iQgAbbaC8M10lzMEgWtiAgDAhwgAQDAC
        ABCMAAAEIwAAwQgAQDACABCMAAAEIwAAwQgAQDACABCMAAAEIwAAwQgAQDACABCMAAAEIwAAwQgAQDAC
        ABCMAAAEIwAAwQgAQDACABCMAAAE+z9wtceXg+mMXgAAAABJRU5ErkJggigAAABAAAAAgAAAAAEAIAAA
        AAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//BAAA/wEAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8CGCrIKhkqzDwA
        P78EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc
        HMYJGynNXBopzJIdJ80aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAcKtQSGyrMhBopzNUcKM4/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeKMsZGSrMnRoqzfYaKcyOACrUBgAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeKMsZGirMoxopzfoaKs3mHSzNNAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/Aioq1AYcOOIJIjPMDxkmzBQWLNIXHSfNGh0nzRod
        J80aFy7QFhkmzBQeLcMREyfEDR8f3wgqKtQGAD+/BAAAfwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZJswUGyvNoBopzfob
        Ks3/GynMshcu0AsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKoDHCrGEhwnyy0ZKctPGirNchoqy5AbKsyoGynLuRspzMQb
        KczLGinN0BspzNUbKczVGynM1Rspzc8bKczLGyrMxhoqzb8aKs22GyrMqhsqzJwbKcuMGinNexopzmka
        KcxWHibQIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ
        M8wKGyrNihopzPkbKs3/GyrN/RsqzHgAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQkyA4bKsxCGyrNihspzcQaKs3mGirM9xsqzP0b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzP4bKcz8GinM+RopzbkZKsweAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAKoDGinNYhoqzPEbKs3/GyrN/xoqzPgdKc5PAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKirUBhkoy0UbKsywGinM7hsqzP4b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKc37GinMmBUq1AwAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGinKMRoqzNobKs3/GyrN/xsqzf8bKs3wHSrQPAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFy65CxopznQb
        KczoGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzfIa
        KsxgAAD/AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEyfEDRopzaQbKsz+GyrN/xsqzf8b
        Ks3/GinN7Rsp0DcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAD+/BBspy24bKszyGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GirL0hwqzSQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARsozVIa
        KszxGyrN/xsqzf8bKs3/GyrN/xspzfMbKtBCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAABwt0S0aKs3dGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzPwaKsuFAD+/BAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAB4twxEbKcy3GyrN/xsqzf8bKs3/GyrN/xsqzf8aKc36HCrMWwAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEcKcx1GyrN/Bsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinN3BgqzioA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaK81NGyrM8hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hopy4YA
        AH8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqKqoGGynMpxsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzPwbKcx6AAD/AgAAAAAAAAAAAAAAAAAAAAAkJNoHGirMoRsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKsy6JyfEDQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAHx+/CBopzLcbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirNxxkz2BQAAAAAAAAAAAAAAAAAAAAAGynOJRopzN0b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN5hop0DEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAACQk2gcbKcyxGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzPAbK89BAAAAAAAAAAAA
        AAAAAAAAABwqzlkaKsz4GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzPwbKsx4AAB/AgAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVf8DGyrNlRsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ksz+GirMfwAA/wEAAAAAAAAAAABV/wMbKcyTGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GinNyR4oyxkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsqz2Ub
        Kcz7GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqy7McOOIJAAAAAAAAAAAkJMgOGinNvhsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xoqzfYaKs1hAAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAaKs8wGirN5hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKczVHCXPGwAAAAAAAAAAGivTHRsqzNkb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrMxhwlzxsAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFy7QCxsqzLAbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynM6RoqzzAA
        AAAAAAAAABss0i4bKczoGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzPkc
        Kc12AFX/AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcKsxbGirN9hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xspzPQbKtBCAAAAAAAAAAAdKsw8GyrN8Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GinN3BkoyzIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAHyrJGBsqzMYbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKs34GyjNUgAAAAAAAAAAGinNQxsqzPQbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzP4bKsyoHy/PEAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEcK8tkGirN9hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM+RopzFYAAAAAAAAAABsq0EIb
        Ksz0GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinN9hsozHAA
        P78EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTCFRsqzLsbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzPka
        KcxWAAAAAAAAAAAeK887GyrN7xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKc3iGyvPQQAA/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEa
        K8xMGinM7Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8aKsz4GSnMUAAAAAAAAAAAHC3LLRspzecbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzMYbKc4lAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAHDjGCRspy5UbKs38GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM8hwozj8AAAAAAAAAABwlzxsbKczWGyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs38GynNphkzzBQA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaKMkmGynMzxsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xoqzOUdKc8rAAAAAAAAAAAX
        LtALGinNuBsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzPkbKs2LFSq/DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB/Ah0pzVca
        KczuGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        KsvNGCTOFQAAAAAAAAAAAAD/AhorzIgbKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynM8xopzHQkJNoHAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAcOMYJGivMjhspzPsbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GirMoyoq1AYAAAAAAAAAAAAAAAAaK81NGynL9Rsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKcztGSjLZDMzzAUA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABst0RwbKsy8GyrM/hsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynM+xopy2gAAAAAAAAAAAAAAAAAAAAAGivKHRoqzdMb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xoqzeYZKstaAD+/BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGivOOhopzdwb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzOQcJ9EtAAAAAAAAAAAA
        AAAAAAAAAAA/vwQbKcyNGyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynN4hsrzVMAP78EAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAABVqgMaKs5fGinM7xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8a
        KcyrGTPMCgAAAAAAAAAAAAAAAAAAAAAAAAAAGivKOhspzegbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKc3hGyvKUwA/vwQA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHDjGCRsqzIQaKsz4GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKcz0GyrOVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw4xgkbKcygGyrM/hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xspzeEbK81TAD+/BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaKNYTGynNpBsqzfwb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrMvBooyRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAGivOOhoqzOQbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirM4xwqzFszM8wFAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAB4t0iIaKcy/GyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM8hopzVcAAP8BAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAq1AYaKs2FGynN+xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKc3nGSnOYyQktgcA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8BHSfNNBoqzdIbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hsqzKcS
        JMgOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGivKHRoqzMEbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzewbKMxwGTPMCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfwIZK9BHGyrM4Bsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzNsZKM0zAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEb
        K89BGynM4hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN8RspzYAiM8wPAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAFX/AxwqzFsbKs3pGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzPIbKsxlAFWqAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAD+/BBsqzGUaKszvGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKcz2GynMkxYsxxcA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqKtQGGSrNbRoqzfAbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzPkbKcuMFy7QCwAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcHMYJGynMehspzPQbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzfobKsyoFi3KIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw44gkaKst9GynM9Bsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzfsaKcukGDDOFQAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUq1Awb
        KsyEGynM8xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/Bopzb0ZKNEyAAD/AQAAAAAAAAAAAAAAAAAAAAAA
        AAAAEyfXDRsqy4saKs33GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzfsa
        KcytGivKHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAFSq/DBsqzHgaKc3tGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKsz+GinM0RspykkA
        P78EAAAAAAAAAAAAAAAAAAAAAAAAAAAeLdIRGyrLlhopzPkbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzPkaKc2kGivKHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfH78IGirOXxsqzN4bKsz+GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKc3iHCjOZBwcxgkAAAAAAAAAAAAAAAAAAAAAAAAAABgkzhUbKc2fGinN+hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzPIbKcyNFy7FFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wMZ
        Ksw8GyrMvBopzfobKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzO8bKMyDGijJEwAAAAAAAAAAAAAAAAAAAAAA
        AAAAHijLGRoqzKMbKc37GyrN/xsqzf8bKs3/GyrM/hoqzN4bKs1nFy7QCwAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAR0nzRobKc2AGinN4xsqzP4bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirM+Bopy6Qd
        K8sjAAD/AQAAAAAAAAAAAAAAAAAAAAAcL88bGinMrBspzfsbKs3/GirN9hkpzLEbKMw4AFX/AwAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMzPMBRoszTkaKculGinM7hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs38GynNwxkqzDwAAKoDAAAAAAAAAAAAAAAAAAAAABkqzB4bKs2qGyrMzhopy2gc
        KtQSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAFSq/DBwqzUgaKc2mGynN6Bsqzf0bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzP4bKc3cGynNXB8fvwgAAAAAAAAAAAAAAAAA
        AAAAGDDOFRoryh0AAP8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGTPMChsozDgaKc2GGyrNzBsqzfEbKsz+GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzO4b
        KsyDGijWEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWqAxUqyRgZ
        KM5FGynNghsqzbkaKczdGyrN8RspzfobKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ksz9GirN9xsqzesaKs3TGinLpRwryjUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAfwIVKtQMHi3KIhsry0AaKsxgGirMfhsrzZQaKculGirMrRopzLca
        Ks2uGyrMpxopzZoaKc2HGynMbxwozFEYLMk0HSfNGh8fvwgAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA
        VaoDMzPMBSQktgcfH78IJCS2Byoq1AYAP78EAAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////////////////////////////////////
        ///////////8//////////D/////////4f/////////D/////////4P/////////B///8AAH//4H//4A
        AAB//Af/+AAAAD/4D//gAAAAH/gP/8AAAAAP8A//gAAAAA/gD/+AAAAAB+AP/wAAAAAH4Af/AAAAAAPA
        B/8AAAAAA8AH/wAAAAADwAP/AAAAAAGAA/+AAAAAAYAB/4AAAAABgAH/gAAAAAGAAP/AAAAAAYAA/8AA
        AAABgAB/wAAAAAGAAD/gAAAAAYAAH+AAAAABgAAf8AAAAAGAAA/4AAAAAYAAB/gAAAABgAAD/AAAAAHA
        AAH+AAAAA8AAAP8AAAADwAAAfwAAAAPgAAA/gAAAB+AAAB/AAAAH8AAAD+AAAAfwAAAH4AAAD/gAAAPw
        AAAf+AAAAfgAAB/8AAAA/AAAP/4AAAB+AAB//wAAAB8AAP//gAAAD4AB///AAAAHwAP//+AAAAPgB///
        8AAAAPAP///8AAAAeD////8AAAA8f////8AAAB//////8AAAH//////+AAAf///////wB///////////
        //////////////////////////////////////////////////////////////////////////////8o
        AAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAD/Ah4oyxkcHMYJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAcHMYJGinNVxsrylMAM8wFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAABwqxhIaKc2GGyrOpxooyRMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGSbMFBopzZobKs3rGivQTAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA
        AKoDAD+/BCoq1AYqKtQGKirUBgAzzAUAVf8DAAB/AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeLdIRGinMmRopzfkbKszGGijJEwAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/8EHyrJGBwryjUb
        KsxVGirNchsqzYoaKc2aGirMoxopzasaKsytGinMrBspy6UbKc2fGyrNlRoqzIkbKcx6GivOaRkqy1kc
        K8xHHyrJGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8fvwgbKMyDGirM+Bsqzf8a
        KsuRAAD/AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEyfXDRspzkka
        KcyZGinN0BsqzewaKcz5GyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ksz+GyrN/RspzfobKc31GyrMqBkmzBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ARsqz1Ua
        KczuGyrN/xsqzP4ZKs1sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEd
        Kc8rGyrMqBsqzfEbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM+RoqzH4zM8wFAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAHibQIRsqzc0bKs3/GyrN/xspzPwaKsxgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAABonyicbKszGGyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xoqzeYZKcw9AAAAAAAAAAAA
        AAAAAAAAAAAAAAAAP78EGyjMgxsqzPwbKs3/GyrN/xsqzP4cKs1tAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAADPMBRopzJIbKs39GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf4b
        Ks2pFSq/DAAAAAAAAAAAAAAAAAAAAAAZLMwoGinM2xsqzf8bKs3/GyrN/xsqzf8aKs2PAAD/AgAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHijLGRoqzNQbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8aKc3tGyrMQgAAAAAAAAAAAAAAAAAA/wEaKstzGynM/Bsqzf8bKs3/GyrN/xsqzf8a
        Kcy/EiTIDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGi3KJxoqy+YbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKsz+GyvNlAA/vwQAAAAAAAAAABIk2g4aKc29GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKczpGCzNNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHCrNJBspzOIb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN0xwlzxsAAAAAAAAAABsrzi8a
        KczoGyrN/xsqzf8bKs3/GyrN/xsqzf8bKsz9GynNgAAA/wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAGijJExspzMsbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynM8xopzUMA
        AAAAAAAAABorzVgaKc36GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN0xcvzyAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAD+/BBsqzJcbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrM/Rspzm8AAAAAAAAAABoqzn0bKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynN+xorzXwA
        P78EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABorzEwbKc3zGyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xspzZQAAP8CAACqAxsqzJcbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzd4aKdAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwq1BIaKszAGyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzasAM8wFAD+/BBopzaQbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzP4bKc2mIiLMDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEb
        K85eGinM9hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzbMfH78IAD+/BBoqzqMb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKcz2HCrNbQBV/wMAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAcKtQSGinMtxsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzbMf
        H78IAAD/AhsqzZYbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynN4hsqzEIA
        AP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGSjORRsqzOobKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzakAM8wFAAAAABspzHobKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzMkZLMwoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCS2Bxkqy4obKc37GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xopzI4AAH8CAAAAABsrylMaKsz4GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf0bKsywHijLGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoryh0a
        Ks3CGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynM/BsqzWYAAAAAAAAAABgrzSkaKczjGyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKc37GirMnBwqxhIAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAEaKc1DGirM5Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM7RsozDgAAAAAAAAAABcu0Asb
        Ks2zGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirM+BopzI4S
        JMgOAAAAAAAAAAAAAAAAAAAAAAAAAAAAP78EGynMbxsqzfUbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynMxRwq1BIA
        AAAAAAAAAAAAAAAcK85jGinM+Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xoqzfYaKc2GEyfXDQAAAAAAAAAAAAAAAAAAAAAAAAAAEiTIDhopy5obKcz8GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks38GinNewAAfwIAAAAAAAAAAAAAAAAaK8odGynMzxsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs31GinNhhMn1w0AAAAAAAAAAAAAAAAAAAAAAAAAABoryh0b
        Ks26GyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8aKs3eFynJKwAAAAAAAAAAAAAAAAAAAAAAAH8CHCrNbRoqzfgbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN9RsqzYofH88QAAAAAAAAAAAA
        AAAAAAAAAAAAAAAaKcoxGirM0Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzfwaKc2GAD//BAAAAAAAAAAAAAAAAAAAAAAAAAAAGCTOFRsqzbob
        Ks3+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xoqzfcb
        KcyTGSbMFAAAAAAAAAAAAAAAAAAAAAAAAP8BGSvLRhspzeEbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzM8dK8sjAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAABwpzT4bKcziGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8aKcz5GinMoRwlzxsAAAAAAAAAAAAAAAAAAAAAAAD/AxspzVwbKs3rGyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM7xopzVcAAP8BAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAA/vwQbKs1nGyrN8Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynN+xspzLEaKNAmAAAAAQAAAAAAAAAAAAAAACoq1AYb
        KcxvGyrN8Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKsz4GyrMhB8f3wgA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcHMYJGijOfRspzfUbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzP0bKc3DHCrLNgAAfwIA
        AAAAAAAAAAAAAAAZM8wKGirMfxspzfUbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzPsb
        KsydHCrGEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFSrUDBoqzn4b
        Ks3xGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ksz+GinM1Rsoy0sAP78EAAAAAAAAAAAAAAAAEyfXDRspy4waKsz4GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GinM+RspzaAVKskYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAABw44gkaK8xqGirM5Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xoqzOUbKs1nHBzGCQAAAAAAAAAAAAAAAB4t0hEbKs2WGinM+Rsqzf8b
        Ks3/GyrN/xsqzf8bKczzGynMjRkmzBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP78EGSjLRRspzcQbKc37GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKszxGinNhhoo1hMAAAAAAAAAAAAAAAAZ
        JswUGirMnBspzfobKs3/GyrM/hopzd0bKs1mFy7QCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ARoryh0bKcuCGynN4RsqzP4b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM+RsozKgb
        Kc4lAAD/AQAAAAAAAAAAFizHFxoqzKIaKc3tGyrMqBgszTQAAKoDAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        M8wFGSjLMhspzJMbKszfGynM/Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzP0aKs3HHCjOPwBVqgMAAAAAAAAAABcu0BYcKM4/EyfEDQAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAADMzzAUeKs4qGirLcxsqzLwbKczoGynN+hsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirM3hopzFYAAP8DAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ARIkyA4aKskwGirMYBoqy5Ea
        Ksy2GyrNzRopzNsbKcziGirM5RspzeEaKs3aGyrNzhsqzLoaKcyZGSrNbRkozTMAAKoDAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAA/wIcOMYJGijWExkqzB4cKs0kGifRJx0ryyMZKsweGSbMFBkzzAoAAKoDAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAA////////AAD///////8AAP///////wAA////////AAD/j/////8AAP8P////
        /wAA/h//////AAD8P//wB/8AAPg//gAAHwAA8D/4AAAPAADgf+AAAAcAAOB/4AAABwAAwH/AAAADAADA
        P8AAAAMAAIA/wAAAAQAAgD/AAAABAACAH8AAAAEAAIAfwAAAAQAAgA/gAAAAAAAAD+AAAAAAAAAH4AAA
        AAAAAAPwAAAAAAAAAfgAAAAAAIAB+AAAAAAAgAD8AAABAACAAHwAAAEAAIAAPgAAAQAAwAAfAAABAADA
        AA+AAAMAAMAAB8AAAwAA4AADwAAHAADwAAHgAAcAAPAAAHAADwAA+AAAOAAfAAD8AAAcAD8AAP4AAA4A
        fwAA/wAABwD/AAD/gAABgf8AAP/gAADH/wAA//gAAH//AAD//gAAf/8AAP//4AP//wAA////////AAD/
        //////8AAP///////wAA////////AAD///////8AAP///////wAAKAAAACgAAABQAAAAAQAgAAAAAABA
        GgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx/fCCQk2gcA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8BGijJJhopzVcnJ9cNAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AP8CHCjOPxoqzLAcKss2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH8CGSvLRhsqzNkbKsuVADPMBQAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//wQSJMgOHyrJGB4m0CEa
        J9EnHCjKLBwo0CwYK80pGynOJRgpzR8fKtQYHCrUEhUqvwwqKtQGAAD/AQAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAABGifOOhsqzdgbKc31GynOSgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAATJ8QNGijNORoqy3MaKcukGynLwxspzNUbKszfGirM5RspzegbKczpGirN5hspzeIa
        Kc3dGynN1RsqzcwaKc2/GirMrRoqzU4AAP8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGSrMHhsqzcIb
        Ks3+GirM5Bot0ScAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVqgMcKMo/GyrMsBsqzewb
        Ksz9GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8a
        Ks3aHijNMwAAAAAAAAAAAAAAAAAAAAAAAAAAKirUBhspy4wbKcz8GyrN/xopzNsZKsweAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEaK8xMGynN4Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hopzK0RIswPAAAAAAAAAAAA
        AAAAAAAAABonzjobKczoGyrN/xsqzf8bKc3iGynHJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ
        JtgUGynNxBsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKcz0GinMVgAAAAAAAAAAAAAAACoq1AYaKc2aGyrM/hsqzf8b
        Ks3/GyrM8hwozj8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGynLNxopzO4bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xoqzLYTJ9cNAAAAAAAAAAAaKMkmGyrN3hsqzf8bKs3/GyrN/xsqzP0bKM13AAD/AQAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAABsrz0AbKcz0GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3sGyjMOAAAAAAA
        AAAAGynNXBopzfobKs3/GyrN/xsqzf8bKs3/GirMwB4t0hEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAa
        Ks8wGyrM6hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/RoqznMAAAAAAAD/AhspzJMbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzfIaKs1OAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGijJExoqzcgbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKcynADPMBRwcxgkaKcy3GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinMtx4t0hEA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAA/wIbKc2BGyrM/Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrNxSIizA8e
        LcMRGirOyBsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xoqzfYbKs1nAAD/AgAAAAAAAAAAAAAAAAAAAAAA
        AAAAGyzNLhspzeIbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzdQfKskYGijJExsqzs4bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN2RoqzzAAAAAAAAAAAAAAAAAAAAAAAAAAADMzzAUbKsuLGyrM/Rsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKc3XHSfNGh8vzxAaKs3IGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzP4b
        KsywGDDOFQAAAAAAAAAAAAAAAAAAAAAAAAAAGynOJRoqzNQbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN0xYs0hcf
        H98IGirNtBsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinN+RsqzIkZM8wKAAAAAAAAAAAA
        AAAAAAAAAAAAfwIaKc1iGynM9Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzcIkJMgOAAB/Ahspzo0bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKszyGSrNbDMzzAUAAAAAAAAAAAAAAAAAAAAAEyfEDRspzZ8b
        Ksz9GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKcufAD+/BAAAAAAbKs5UGirM+Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzOoZKstaAFX/AwAAAAAAAAAAAAAAAAAAAAAaKMkmGyrNzBsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKc37GyrMZQAAAAAA
        AAAAFyfPIBsqzdcbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM4xwpz1AA
        AKoDAAAAAAAAAAAAAAAAAAD/ARspykkaKs3mGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GynN4h0pySsAAAAAAAAAAAAAvwQbKs2LGyrN/Rsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKszgGSnLTwAAqgMAAAAAAAAAAAAAAAAA
        P/8EHCrNbRspzfMbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrM/hspy58kJNoHAAAAAAAAAAAAAAAAGybNLhsqzd4bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xspzeEbK81SAD+/BAAAAAAAAAAAAAAAABcu0AsaKcyOGynN+hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzOkZKcw9AAAAAAAAAAAA
        AAAAAAAAAAAA/wMbKM13GinM+Rsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GirN5BspzVwzM8wFAAAAAAAAAAAAAAAAGCTOFRsqzKgbKs38GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzPwbKc6NJCS2BwAAAAAAAAAAAAAAAAAAAAAAAAAAGSbMFBoqza4b
        Ksz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKszqGirMaxwcxgkA
        AAAAAAAAAAAAAAAXJ88gGyrNuxsqzP4bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Kc3DGCnNHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYK80pGirNyBsqzP4bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzPEcKs5/IiLMDwAAAAAAAAAAAAAAABwo0Cwa
        Kc3JGyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKszaGSvLOwAAAAEAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAD/ARwryjUaKczLGyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GirM9xsqzpceKMsZAAAAAAAAAAAAAP8BGynLNxopzNMbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8aKc3dGynOSgAA/wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AP8BGybHLhopzbgbKc37GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Kc37GynMshgrzSkAAP8BAAAAAAAA/wEbJ8tAGyrM2Rsqzf8bKs3/GyrN/xsqzP4bKczPGinNQwAA/wIA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdJ80aGynLjBsqzewb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf0aKszLGyvPQQAAqgMA
        AAAAAAB/Ahkoy0YaKczdGyrN/xoqzfYbKs2pFynPKwAA/wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQk2gcYKs1IGirNthspzPQbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzeEaKc1iHBzGCQAAAAAAAP8CGyjLSxspzLob
        Ks1mHx/PEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAB8vzxAcKMxRGinMqxoqzOUbKc37GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GirN8BopzYcZJswUAAAAAAAA/wIiIswPAAB/AgAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAABw4xgkcLcstGyrNZxoqzaEaKc3JGyrM4BsqzewbKszyGynM9BoqzfEbKs3rGyrM3xopzckb
        Kc2fGSjNMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        M8wFHCrGEh0ryyMZKMsyGSrMPBsry0AaK846GirPMB4u0CEeLdIRMzPMBQAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/
        /////wAAAP//////AAAA//////8AAAD/P////wAAAPw/////AAAA+H////8AAADwf/gADwAAAOD/wAAH
        AAAA4P8AAAcAAADA/gAAAwAAAMD+AAADAAAAgP4AAAEAAACAfgAAAQAAAIB+AAABAAAAAH4AAAAAAAAA
        PgAAAAAAAAAfAAAAAAAAAB8AAAAAAAAAD4AAAAAAAAAHgAAAAAAAAAPAAAAAAACAAeAAAQAAAIAA4AAB
        AAAAgABwAAEAAADAADgAAwAAAMAAHAADAAAA4AAOAAcAAADwAAcABwAAAPAAAwAPAAAA+AAAgB8AAAD+
        AABAPwAAAP8AACD/AAAA/8AAEf8AAAD/8AAf/wAAAP/+AD//AAAA//////8AAAD//////wAAAP//////
        AAAA//////8AAAD//////wAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AQBV/wMAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABw44gkbK8tAFizHFwAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfL88QGyjMgxsozGUA
        AKoDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEiTaDhoqzZEa
        KczRGCnNHwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJCTaBxgpzR8ZK887GyrOVBsqzWca
        Ks1yGyrMeBkpzXYbKc5uHCvOZBoozVgbKctKGivOOh8vzxAAAAAAAAAAAAAAAAAAAAAAAAAAADMzzAUb
        Kcx6GirM9xopzKsqKtQGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx+/CBspy0obKsynGinM2xsqzfEa
        Kc36GyrN/RsqzP4bKs3+GyrM/hsqzP4bKsz9GynN+xoqzfcaKs3wGynMkxcu0AsAAAAAAAAAAAAAAAAA
        AAAAGinKRBspzOkbKs3/GynNlAAAfwIAAAAAAAAAAAAAAAAAAAAAAAAAACoq1AYbKs13GinM7hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKczzGynKXQAA/wEA
        AAAAAAAAABIkyA4aKsu0GyrN/xsqzf8bKc2gAACqAwAAAAAAAAAAAAAAAAAAAAAAAAAAGCzNNBopzecb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8a
        Kc3JHijLGQAAAAAAAAAAHCvMRxoqzfEbKs3/GyrN/xspzcQfL88QAAAAAAAAAAAAAAAAAAAAAAAAAAAb
        Kc1cGyrM/Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xoqzPgcKsxbAAAAAAAAqgMaKcySGyrN/xsqzf8bKs3/GyrN7BsozDgAAAAAAAAAAAAAAAAA
        AAAAAAAAABopzVcbKc36GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xopzaUqKtQGHy/PEBoqzccbKs3/GyrN/xsqzf8bKsz+GynMjQA/vwQA
        AAAAAAAAAAAAAAAAAAAAGSjLMhspzOobKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirM0yEs0hceLcoiGyrM4Bsqzf8bKs3/GyrN/xsqzf8b
        Kc3iGSjNMwAAAAAAAAAAAAAAAAAAAAATJ8QNGirMthsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKczoFynJKxwtyy0bKszqGyrN/xsqzf8b
        Ks3/GyrN/xsqzP4aKc2lEiTIDgAAAAAAAAAAAAAAAAAAAAAaKMpYGynN9Rsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopze8cKss2HC3LLRsqzOob
        Ks3/GyrN/xsqzf8bKs3/GyrN/xspzfUaKsxrAFX/AwAAAAAAAAAAAAAAAB8vzxAbKcyyGyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GinM7xwqyzYX
        LtAhGyrM3xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xoqzeMaKc5EAAD/AQAAAAAAAAAAAAAAAB0pzD0a
        KszlGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8a
        Ks3mGCvNKSIizA8bKc3DGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xspzc8aKs8wAAAAAAAAAAAA
        AAAAPz+/BBsqzngaKs34GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzc0ZJswUAAD/AhkqzYobKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hoqzMEa
        KNAmAAAAAAAAAAAAAAAAHCrGEhopzKsbKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GinMmQA/vwQAAAAAHCnJPhopze0bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/RsqzbkcKs0kAAAAAAAAAAAAAAAAGSzSKBsqy80bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xspzPMbKMtLAAAAAAAAAAAXLrkLGivNphsqzP4bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrM/RsqzLoaKNAmAAAAAAAAAAAAAP8BGinJQxspzeEbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirMtiIizA8AAAAAAAAAAAAAAAAbKcs3GynL4Rsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/RoqzcAbLM0uAAD/AQAAAAAAAKoDGynNXBsqzewb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzOoZKMtFAAAAAAAAAAAAAAAAAAAAAAAA/wMa
        KctoGyrM8hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hsqzcwZK887AAB/AgAAAAAq
        KtQGGyrNcRspzPMbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKs33GinLfCoq1AYAAAAAAAAAAAAAAAAA
        AAAAAAAAABw4xgkaKsx/GynM9Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzdkZ
        KctPAD+/BAAAAAAZM8wKGynNgRoqzfYbKs3/GyrN/xsqzf8bKs3/GinM+Rspy5UiIswPAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAABcu0AsaKcx1GyrN6xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopzecaKMxqGTPMCgAAAAATJ9cNGynMjRoqzPgbKs3/GyrN/xspzPMbKc2MHCrGEgAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACoq1AYaKs1OGinNyRspzfsbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzfIbKs2KGSbMFAAAAAAfL88QGynNlBoqzfcaKs3aGyrMZRcu0AsA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEaK8odGynMehsqzdQa
        Kcz5GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzfoaKc6sGSbMKAAA/wEcKtQSHCvOZBwo0CwA
        AP8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AP8CGSrUHhoqzl8bKs6nGynM1hopze0aKsz4GynN+xsqzfwbKc36GinN9hspzegbKcyeFy7QFgAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAACoq1AYdJ80aHCvKNRorzEwcKsxbGirLXxopzVcZK8tGGyvOLxcu0BYA
        Vf8DAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAA///////////8////+P////D////h/gAHwfgAA8HwAAGB8AABgfAAAQHwAAAA
        8AAAAPAAAAB4AAAAOAAAABwAAAAcAAAADgAAgAcAAYADAAHAAIADwABAA+AAIAfwABAP+AAIH/wAAD//
        AAP//+AD//////////////////////8oAAAAGAAAADAAAAABACAAAAAAAGAJAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ARgpzR8dJ80aAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AP8BGSrQPBspzYESJMgOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAzzAUZM8wKEiTIDiIizA8T
        J9cNGTPMCioq1AYAAKoDAAAAAAAAAAAAAAAAAAAAAAAAAAAdLM00GynNzxoqzl8AAAAAAAAAAAAAAAAA
        AAAAAAAAABUqvwwbKsxCGynNgBsqzKgaKc29GyrNxRoqzccbKc3DGyrMvBsqzLAbKsycGSvPOwAA/wEA
        AAAAAAAAABgkzhUbKc24GyrN8hgpzT4AAAAAAAAAAAAAAAAAAAAAGSbMFBoqzJwaKs3wGyrM/hsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrMxhoryh0AAAAAAAD/ARsqzWcaKs34GinN9hwqyUgA
        AAAAAAAAAAAAAAAAAAAAHCnLYxopzfobKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GynN+xsozXcAAH8CIjPMDxoqzMAbKs3/GyrM/hspzHoAAP8BAAAAAAAAAAAAAAAAGyrMhBsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzckZJswUGirPMBsqzOob
        Ks3/GyrN/xsqzMYYJM4VAAAAAAAAAAAAAAAAGSnLYxspzfsbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xopzO4bKcs3GivNTRoqzfgbKs3/GyrN/xoqzfcbKs1mAAB/AgAAAAAA
        AAAAGi3RJxsqzd4bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xopzfob
        K81TGSjLWRspzfsbKs3/GyrN/xsqzf8bKc3XHCjQLAAAAAAAAAAAAD+/BBopzIgbKs38GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzfwbK81dGivNTRoqzPgbKs3/GyrN/xsqzf8b
        Ksz+GirNrhgkzhUAAAAAAAAAAB4lyiIbKczPGyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xopy/obK81SGyzNLhspzegbKs3/GyrN/xsqzf8bKs3/GinN+hoqzZETJ9cNAAAAAAAA/wEb
        Ks5UGinN7hsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzesZKM0zEyfXDRsqzLsb
        Ks3/GyrN/xsqzf8bKs3/GyrN/xoqzfYbKc2CFy7QCwAAAAAkJNoHGirNhRopzPkbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xoqzMEfL88QAAAAARoqy18aKs32GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Kcz0GynNgRUq1AwAAAAAGijJExsqzKgbKsz9GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GirN+Bopy2gA
        AP8BAAAAAB4twxEaKs2uGyrM/hsqzf8bKs3/GyrN/xsqzf8bKs3/GynN9RsqzYoeLcMRAAAAAB4u0CEa
        Kc2/GyrM/hsqzf8bKs3/GyrN/xsqzf8bKsz+GinNuBgkwhUAAAAAAAAAAAAAAAAcKMosGyrNzBsqzP4b
        Ks3/GyrN/xsqzf8bKs3/GyrN/xoqzfgaKs2cHijLGQAAAAAbK84vGyrNzRsqzf8bKs3/GyrN/xsqzf8b
        KczVHSfNNAAAAAAAAAAAAAAAAAAAAAAAAP8BGCzNNBspzcQbKsz9GyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Kc37GyrNsxgrzSkAAH8CGifOOhspzNUbKs3/GyrM/hspzc8cKM4/AAD/AQAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAARcu0CEbKs2VGyrN7Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrM/hspzcwbKsxCAD+/BBsry0Eb
        KczPGynMphcpySsAAP8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfH78IGyvLQBoqzJwa
        Ks3aGynN9Rsqzf0bKs3/GyrN/xsqzP4bKszfGinMVgAzzAUYKc0fFSrUDAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMzzAUXJ8cgHCvMRxoqzGsbKc2BGirNhRsqzngb
        KcpdGyzNLgAAqgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////APv//wDj//8Aw/AHAMfAAQCHgAEAB4AAAAOAAAAD
        gAAAAYAAAAGAAAAAwAAAAEAAAAAgAAAAEAAAgAgBAMAEAwDAAAMA4AAHAPgAHwD+AH8A////AP///wD/
        //8AKAAAABQAAAAoAAAAAQAgAAAAAACQBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAD/ASoq1AYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzzAUaKc1DHCrNJAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKoDGynNXRopzJgc
        HMYJAAAAAAAAAAAAAAAAAAD/AhgpzR8aKMxMGynLbhspy4EaKc2HGyrMgxsqzHkaKctpGinNQwAzzAUA
        AAAAAAAAABooyTkbKc3hGynNgQAAAAAAAAAAAAAAAAA/vwQaKsxgGynN1RoqzPcbKsz+GyrN/xsqzf8b
        Ks3/GyrN/xsqzP4aKs3mGinORAAAAAAcOMYJGynMpxsqzf4bKc2MAAD/AQAAAAAAAAAAHibIIRoqzdob
        Ks3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKcyyFSrUDBsrzi8aKc3nGyrN/xoqzcAf
        L88QAAAAAAAAAAAdKc8rGynM6Bsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzOwc
        K841HCrLWhspzfsbKs3/GyrM8hoqyk4AAAAAAAAAABwqxhIbKszGGyrN/xsqzf8bKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GyrN/BoqzGAbK8xwGyrN/hsqzf8bKs3/GinNvx4oyxkAAAAAAAD/ARspy24a
        Kc35GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/HCvKdRopzWgbKs39GyrN/xsqzf8b
        Kcz7GynLjBkzzAoAAAAAFizHFxoqzb8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzP4c
        KsttGinKRBspzfMbKs3/GyrN/xsqzf8bKczzGynObioq1AYAAAAAGinNQxoqzeYbKs3/GyrN/xsqzf8b
        Ks3/GyrN/xsqzf8bKs3/GynN9RwqzUgWLMcXGinMyxsqzf8bKs3/GyrN/xsqzf8bKs3sGSvOZDMzzAUA
        P78EGynMbxspzfUbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8aKczQHSfNGgAA/wEaKc1oGirM9xsqzf8b
        Ks3/GyrN/xsqzf8bKszsGinNaCQk2gcXLtALGirNkBopzfobKs3/GyrN/xsqzf8bKs3/GinM+RsozHAA
        AH8CAAAAACIzzA8aKs2hGynM/Bsqzf8bKs3/GyrN/xsqzf8aKczvGyrMeBUqvwwZJswUGynMphsqzfwb
        Ks3/GyrN/xsqzP0aKcyrGijJEwAAAAAAAAAAAAAAABwlzxsaKculGinM+Rsqzf8bKs3/GyrN/xsqzf8b
        Kc31GirNkBcuxRYbLdEcGynMshsqzP0bKcz7GyrNsBcnzyAAAAAAAAAAAAAAAAAAAAAAAAAAABwqxhIZ
        Kc12GinN3BsqzfwbKs3/GyrN/xsqzf8bKc36GirNrhkmzCgeLdIiGyrNqRsqzIQWLMcXAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAqgMZLMwoGinMdRspzbkaKczbGynM6RsqzOobKc3hGirNmxcuxRYV
        KtQMMzPMBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP8BFy7QCxor0x0c
        KMosGyzNLhspxyUaKNYTAACqAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///AA5//wAMf/8ACHABAAjgAQAAYAAAAGAAAABgAAAAIAAAAB
        AAAAAIAAAAAAAAAAAAAAgAAQAMAAMADgAHAA8ADwAPwD8AD///AA///wACgAAAAQAAAAIAAAAAEAIAAA
        AAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcHMYJGCTOFQAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVKtQMGSnLbhks0igAAAAAAAAAAAAAAAAZ
        M8wKGynOJRorzjoaKc1DGyrMQhkryzsbLM0uFy7QCwAAAAAAAKoDGynLbhsqzLwSJMgOAAAAAAAAAAAc
        KMosGinMrBspzeIbKs3xGynN9RspzfUbKszyGynM6RspzHoAP78EHSvLIxsqzNkbKs3MGijJEwAAAAAA
        AP8CGyrLlhsqzP4bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKszgGCrOKhsoy14bKcz7GinN7hwozj8A
        AAAAAAD/AhsqzJcbKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/BsqzWcaKs2FGyrN/xsqzf4b
        KcynEyfEDQAAAAAaKs1OGynM8xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrN/xsqzf8bKc2MGyrMhBsqzf8b
        Ks3/GynN9RoqzGsAP78EEyfXDRopzasbKsz+GyrN/xsqzf8bKs3/GyrN/xsqzf8bKs3/GyrNixwqzFsb
        Kc36GyrN/xsqzf8aKcznHCjMUQAA/wIaKcoxGirM2hsqzf8bKs3/GyrN/xsqzf8bKs3/GynN+xopzWIX
        J88gGynM1Rsqzf8bKs3/GyrN/xsqzOAaK8pNADPMBRopzVcbKs3sGyrN/xsqzf8bKs3/GyrN/xoqzNoc
        Ks0kAAD/AhsqzGUbKczzGyrN/xsqzf8bKs3/GynM4hopzVcXLrkLGirLcxspzfMbKs3/GyrN/xopzPYb
        KcxvAACqAwAAAAAZM8wKGinNfBopzfAbKs3/GyrN/xsqzf8bKszqGynLbhkmzBQbKs6DGirN9hspzfMa
        KcyIFSrUDAAAAAAAAAAAAAAAAB8fvwgbKsxVGynNxBspzfUbKs3/GyrN/xspzfMaKcyOHSvLIxsqzHka
        Ks1hGTPMCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/ARgkzhUbKMtLGyrOgxoqzKMbKc2mGivMjhoqyTAA
        AKoDAAD/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAVaoDAD+/BAAA/wEA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAM//AACOAQAADAAAAAgAAAAIAAAABAAAAAAAAAAA
        AAAAAAAAAAAAAACAAQAAwAMAAOAHAAD8PwAA//8AAA==
</value>
  </data>
</root>
LB_SmartVision/logo.ico
LB_SmartVision/ref/halcondotnet.dll
Binary files differ
LB_SmartVisionCameraDevice/CameraUserRole.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVisionCameraDevice
{
    /// <summary>
    /// ç›¸æœºå‚数可视化权限
    /// </summary>
    public enum CameraUserRole
    {
        /// <summary>
        /// åˆçº§
        /// </summary>
        Primary,
        /// <summary>
        /// ä¸“å®¶
        /// </summary>
        Expert,
        /// <summary>
        /// å¤§å¸ˆ
        /// </summary>
        Master,
    }
}
LB_SmartVisionCameraDevice/Data/StateIcon.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVisionCameraDevice.Data
{
    /// <summary>
    /// StateIcon
    /// </summary>
    public class StateIcon
    {
        /// <summary>
        /// Connect
        /// </summary>
        public const string Connect = "Connect";
        /// <summary>
        /// DisConnect
        /// </summary>
        public const string DisConnect = "disConnect";
        /// <summary>
        /// Start
        /// </summary>
        public const string Start = "Start";
        /// <summary>
        /// StartRepeat
        /// </summary>
        public const string StartRepeat = "StartRepeat";
    }
}
LB_SmartVisionCameraDevice/DeviceType.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LB_SmartVisionCameraDevice
{
    /// <summary>
    /// CameraType
    /// </summary>
    public enum DeviceType
    {
        /// <summary>
        /// 6000系列扫描头子
        /// </summary>
        PHM6000Series,
        /// <summary>
        /// 5000系列扫描头子
        /// </summary>
        PHM5000Series,
        /// <summary>
        /// 2000系列扫描头子
        /// </summary>
        PHM2000Series
    }
}
LB_SmartVisionCameraDevice/LB_SmartVisionCameraDevice.csproj
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\LB_SmartVisionCameraSDK\LB_SmartVisionCameraSDK.csproj" />
    <ProjectReference Include="..\LB_SmartVisionCommon\LB_SmartVisionCommon.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="ref\" />
  </ItemGroup>
</Project>
LB_SmartVisionCameraDevice/PHM6000/CaliModel.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
using LB_SmartVisionCommon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVisionCameraDevice.PHM6000
{
    [JsonObject(MemberSerialization.OptOut)]
    [TypeConverter(typeof(PropertySorter))]
    [DefaultProperty("平面区")]
    public class CaliModel
    {
        protected const string ROIInfo = "标定ROI数据";
        protected const string CameraInfo = "相机安装参数";
        [Category(ROIInfo), PropertyOrder(10)]
        [DisplayName("平面区")]
        public string Plane { get; set; } = "0,0,0,0";
        [Category(ROIInfo), PropertyOrder(11)]
        [DisplayName("孔区1")]
        public string Hole1 { get; set; } = "0,0,0,0";
        [Category(ROIInfo), PropertyOrder(12)]
        [DisplayName("孔区2")]
        public string Hole2 { get; set; } = "0,0,0,0";
        [Category(ROIInfo), PropertyOrder(13)]
        [DisplayName("孔区3")]
        public string Hole3 { get; set; } = "0,0,0,0";
        //[Browsable(false)]
        [Category(CameraInfo), PropertyOrder(14)]
        [DisplayName("x倒序")]
        public int IsReverse { get; set; } = 0;        //x倒序
        [Category(CameraInfo), PropertyOrder(15)]
        [DisplayName("z相对")]
        //[Browsable(false)]
        public int IsOpposite { get; set; } = 0;       //z相对
        [Category(CameraInfo), PropertyOrder(16)]
        [DisplayName("标准距离")]
        //[Browsable(false)]
        public float fStdDistance { get; set; } = 325;
        [Category(CameraInfo), PropertyOrder(17)]
        [DisplayName("X轴中心")]
        //[Browsable(false)]
        public float fXCenter { get; set; } = 215.04f;
        [Category(CameraInfo), PropertyOrder(18)]
        [DisplayName("Xè½´")]
        //[Browsable(false)]
        public float x { get; set; } = 0;
        [Category(CameraInfo), PropertyOrder(19)]
        [DisplayName("Yè½´")]
        //[Browsable(false)]
        public float y { get; set; } = 0;
        [Category(CameraInfo), PropertyOrder(20)]
        [DisplayName("Zè½´")]
        //[Browsable(false)]
        public float z { get; set; } = 417.75f;
        [Category(CameraInfo), PropertyOrder(21)]
        [DisplayName("X轴角度")]
        //[Browsable(false)]
        public float xAngle { get; set; } = 0;
        [Category(CameraInfo), PropertyOrder(22)]
        [DisplayName("Y轴角度")]
        //[Browsable(false)]
        public float yAngle { get; set; } = 0;
        [Category(CameraInfo), PropertyOrder(23)]
        [DisplayName("Z轴角度")]
        //[Browsable(false)]
        public float zAngle { get; set; } = 0;
    }
}
LB_SmartVisionCameraDevice/PHM6000/CaliOutLine.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
using LB_SmartVisionCommon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVisionCameraDevice.PHM6000
{
    [JsonObject(MemberSerialization.OptOut)]
    [TypeConverter(typeof(PropertySorter))]
    [DefaultProperty("轮廓线")]
    public class CaliOutLine
    {
        protected const string ROIInfo = "标定ROI数据";
        [Category(ROIInfo), PropertyOrder(1)]
        [DisplayName("轮廓线区域")]
        public string OutLine { get; set; } = "0,0,0,0";
    }
}
LB_SmartVisionCameraDevice/PHM6000/PHM6000Sensor.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1230 @@
using LB_SmartVisionCameraSDK;
using LB_SmartVisionCameraSDK.PHM6000;
using LB_SmartVisionCommon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVisionCameraDevice.PHM6000
{
    /// <summary>
    /// PHM6000Series-Sensor
    /// </summary>
    public class PHM6000Sensor
    {
        public IntPtr Entry { get; set; }//连接传感器的接口
        public string IP { get; set; }//传感器IP
        public string SerialNo { get; set; }//传感器序列号
        public int Port { get; set; }//端口
        List<byte[]> LineDatas { get; set; } = new List<byte[]>();//存储扫描到的行数据
        public IntPtr CaliEntry = IntPtr.Zero;//测量标定入口
        readonly object _lock = new object();
        readonly object _lockIntPtr = new object();
        //public PanelControl PointPanel { get; set; }
        //WaitForm ssm;
        public int Index { get; set; }//传感器序号,主要用于标定
        public IntPtr lightPic = IntPtr.Zero;//亮度图
        public IntPtr deepPic = IntPtr.Zero;//深度图
        public IntPtr pointPic = IntPtr.Zero;//点云图
        public IntPtr outlinePic = IntPtr.Zero;//轮廓图
        public IntPtr outlineMainPic = IntPtr.Zero;//主界面轮廓图
        public CaliModel CaliModel { get; set; }//测量用参数
        public CaliOutLine CaliOutLine { get; set; }//测量用参数
        public bool isContinuousScan = false;
        CancellationTokenSource lightCts;
        CancellationTokenSource deepCts;
        CancellationTokenSource pointCts;
        CancellationTokenSource outlineCts;
        //PILOT2D_FUNC func2d;
        //VTK3D_FUNC func3d;
        AcquisitionCallbackZA sendDatacallback;//回调委托(行数据发送给本系统)
        string path = string.Empty;
        //int currentRowNumber = 0;
        /// <summary>
        /// åˆå§‹åŒ–传感器
        /// </summary>
        /// <param name="ip">传感器IP</param>
        /// <param name="serialNo">传感器序列号</param>
        /// <param name="port">传感器端口</param>
        /// <param name="localPtr">本系统用于承载图片的控件指针</param>
        public PHM6000Sensor(string ip, string serialNo, int port, int index/*, WaitForm ssm*/)
        {
            this.IP = ip;
            this.SerialNo = serialNo;
            this.Port = port;
            this.Index = index;
            //this.ssm = ssm;
            CaliEntry = SysCalibration.CreateSysCalibrationEntry();//测量标定入口
        }
        public int GetLineCount()
        {
            int count;
            lock (_lock)
            {
                count = LineDatas.Count;
            }
            return count;
        }
        public List<byte[]> GetLineDatas()
        {
            LineDatas.Clear();
            var o = new List<byte[]>();
            lock (_lock)
            {
                IntPtr pData = IntPtr.Zero;
                ulong nIndex = 0;
                //Config config;
                //if (!IP.Equals("0.0.0.0"))
                //{
                //    config = GetConfig();
                //}
                //else
                //{
                //    config = new Config();
                //}
                uint count = 0;
                while ((pData = PHM6000Profiler.GetLineDataByIndex(Entry, nIndex)) != IntPtr.Zero)
                {
                    unsafe
                    {
                        LBLineHeadInfo pInfo = Marshal.PtrToStructure<LBLineHeadInfo>(pData);
                        count = pInfo.nPointCount;
                    }
                    LBLineDataZA lBLineDataZA = new LBLineDataZA
                    {
                        info = new LBLineHeadInfo(),
                        data = new LBPointZA[count]
                    };
                    long length = Marshal.SizeOf(lBLineDataZA) + Marshal.SizeOf(new LBPointZA()) * count;
                    int datacount = int.Parse(length.ToString());
                    byte[] byteArray = new byte[length];
                    Marshal.Copy(pData, byteArray, 0, datacount);
                    LineDatas.Add(byteArray);
                    nIndex++;
                }
                o.AddRange(LineDatas);
            }
            return o;
        }
        IntPtr Temp = IntPtr.Zero;
        public IntPtr GetLineLastData()
        {
            lock (_lock)
            {
                IntPtr pData = IntPtr.Zero;
                Temp = IntPtr.Zero;
                ulong nIndex = 0;
                uint count = 0;
                while ((pData = PHM6000Profiler.GetLineDataByIndex(Entry, nIndex)) != IntPtr.Zero)
                {
                    //Marshal.FreeHGlobal(Temp);
                    Temp = pData;
                    //SysCalibration.AddLineDataArray(CaliEntry, Index, Temp, false, 1);
                    SysCalibration.SetLineDataArray(CaliEntry, Index, Temp);
                    nIndex++;
                }
                if (pData == IntPtr.Zero)
                {
                }
            }
            return Temp;
        }
        #region åˆ›å»ºå›¾ç‰‡æŽ§ä»¶
        public IntPtr CreatePicPtr(IntPtr localPtr, EnumFetchPicType picType)
        {
            IntPtr ptr = IntPtr.Zero;
            PHM6000SensorConfig config;
            if (!IP.Equals("0.0.0.0"))
            {
                config = GetConfig();
            }
            else
            {
                config = new PHM6000SensorConfig();
            }
            switch (picType)
            {
                case EnumFetchPicType.light:
                    if (lightPic == IntPtr.Zero)
                    {
                        ptr = Pilot2D.CreatePilot2DEntry(localPtr);
                        Pilot2D.SetImageSize(ptr, 4096, config.ScanLineCount);
                        lightPic = ptr;
                    }
                    break;
                case EnumFetchPicType.deep:
                    if (deepPic == IntPtr.Zero)
                    {
                        ptr = Pilot2D.CreatePilot2DEntry(localPtr);
                        Pilot2D.SetImageSize(ptr, 4096, config.ScanLineCount);
                        deepPic = ptr;
                    }
                    break;
                case EnumFetchPicType.pointCloud:
                    if (pointPic == IntPtr.Zero)
                    {
                        ptr = PclEntry.CreatePCLWindow(localPtr);
                        //PclInvoke.RenderPCLWindow(ptr, 800, 600);
                        pointPic = ptr;
                    }
                    break;
                case EnumFetchPicType.outline:
                    if (outlinePic == IntPtr.Zero)
                    {
                        ptr = Pilot2D.CreatePilot2DEntry(localPtr);
                        Pilot2D.SetImageSize(ptr, 4096, 2048);
                        outlinePic = ptr;
                    }
                    break;
                case EnumFetchPicType.mainOutLine:
                    if (outlineMainPic == IntPtr.Zero)
                    {
                        ptr = Pilot2D.CreatePilot2DEntry(localPtr);
                        Pilot2D.SetImageSize(ptr, 4096, 2048);
                        outlineMainPic = ptr;
                    }
                    break;
            }
            return ptr;
        }
        #endregion
        event AcquisitionCompletedCallback acquisitionCompletedCallback = null;
        public event AcquisitionCompletedCallback acquisitionCompleted = null;
        public event ShowDebugInfoCallback registerShowDebugInfoCallback = null;
        public void RegisterShowDebugInfoCallback(ShowDebugInfoCallback callback)
        {
            PHM6000Profiler.RegisterShowDebugInfoCallback(Entry, callback);
        }
        PILOT2D_FUNC func2d = new PILOT2D_FUNC
        {
            AddBarycentreDataZA = Pilot2D.AddBarycentreDataZA,
            AddDepthData = Pilot2D.AddDepthData,
            AddIntensityData = Pilot2D.AddIntensityData,
            ClearAllPoints = Pilot2D.ClearAllPoints,
            RefreshPilot2D = Pilot2D.RefreshPilot2D,
            SetImageSize = Pilot2D.SetImageSize,
        };
        VTK3D_FUNC func3d = new VTK3D_FUNC
        {
            AddZAPoints = PclEntry.AddZAPoints,
            ClearPCLPoints = PclEntry.ClearPCLPoints,
            GetPointCloudBound = PclEntry.GetPointCloudBound,
            RenderPCLWindow = PclEntry.RenderPCLWindow,
            SetLookUpTableRange = PclEntry.SetLookUpTableRange,
            ShowCubeAxes = PclEntry.ShowCubeAxes,
            ShowLookUpTable = PclEntry.ShowLookUpTable,
            UpdatePCLPointColors = PclEntry.UpdatePCLPointColors,
        };
        public void StartDataProcess()
        {
            //SetShowHandles(Entry, lightPic, deepPic, outlinePic, pointPic);
            acquisitionCompletedCallback += PHM6000Sensor_acquisitionCompletedCallback;
            PHM6000Profiler.SetPilot2dFunc(Entry, func2d);
            PHM6000Profiler.SetVTK3dFunc(Entry, func3d);
            PHM6000Profiler.RegisterAcquisitionCompletedCallback(Entry, acquisitionCompletedCallback, new IntPtr());
        }
        public void CameraShow()
        {
            PHM6000Profiler.SetShowHandles(Entry, lightPic, deepPic, outlinePic, pointPic);
        }
        public void MainShow()
        {
            PHM6000Profiler.SetShowHandles(Entry, lightPic, deepPic, outlineMainPic, pointPic);
        }
        public IntPtr hWnd;
        private void PHM6000Sensor_acquisitionCompletedCallback(IntPtr pInstance, int nOption)
        {
            if (nOption == 2)
            {
                //显示点云
                bool result = PclEntry.PostMessage(hWnd, CommonVar.WM_RENDER_VTK, 0, (ulong)pInstance);  // m_hMainWnd是主窗口句柄
            }
            if (acquisitionCompleted != null)
            {
                acquisitionCompleted(pInstance, nOption);
            }
        }
        public IntPtr PInstance;
        #region è¿žæŽ¥ä¼ æ„Ÿå™¨
        public bool ConnectCamera()
        {
            Entry = PHM6000Profiler.CreateCameraEntry();
            var addr = Encoding.ASCII.GetBytes(IP);
            var result = PHM6000Profiler.ConnectToCamera(Entry, addr, Port);
            if (result == 0)
            {
                return true;
            }
            return false;
        }
        #endregion
        #region ä»Žä¼ æ„Ÿå™¨èŽ·å–å‚æ•°é…ç½®
        public PHM6000SensorConfig GetConfig()
        {
            //获取参数
            PHM6000SensorConfig config;
            if (IP.Equals("0.0.0.0"))
            {
                config = new PHM6000SensorConfig();
                return config;
            }
            //先从本地获取配置
            path = $"{SerialNo}-config.lb";
            if (File.Exists(path))
            {
                config = ConfigManager<PHM6000SensorConfig>.LoadConfig<PHM6000SensorConfig>(@path);
            }
            else
            {
                config = new PHM6000SensorConfig();
            }
            //-----------------
            PropertyInfo[] props = config.GetType().GetProperties();
            foreach (PropertyInfo p in props)
            {
                //跳过自定义参数
                var iscustomAttr = p.GetCustomAttribute<IsCustomAttribute>();
                if (iscustomAttr != null) continue;
                var nameId = Enum.Parse(typeof(EnumNameId), p.Name);
                int intValue = 0;
                double doubleValue = 0;
                int enumValue = 0;
                var id = Convert.ToInt32(nameId);
                var rst = PHM6000Profiler.GetProfilerParameter(Entry, id, ref intValue, ref doubleValue, ref enumValue);
                if (rst == 0)
                {
                    if (p.PropertyType == typeof(int))
                    {
                        p.SetValue(config, intValue);
                    }
                    else if (p.PropertyType == typeof(float))
                    {
                        var value = Convert.ToSingle(doubleValue);
                        p.SetValue(config, value);
                    }
                    else
                    {
                        if (p.Name.Equals("ROI"))
                        {
                        }
                        else
                        {
                            p.SetValue(config, enumValue);
                        }
                    }
                }
            }
            return config;
        }
        #endregion
        void SetTargetParam(PHM6000SensorConfig config)
        {
            TARGET_INFO tARGET_INFO = new TARGET_INFO()
            {
                //fHeight = config.fHeight,
                //fWidth = config.fWidth,
                //fMarginRangeX = config.fMarginRangeX,
                //fMarginRangeY = config.fMarginRangeY,
                //fMarginX = config.fMarginX,
                //fMarginY = config.fMarginY,
                //nPartitionX = config.nPartitionX,
                //nPartitionY = config.nPartitionY,
            };
            SysCalibration.SetTargetParameter(CaliEntry, tARGET_INFO);
        }
        #region è®¾ç½®å‚æ•°
        public bool SetConfig(PHM6000SensorConfig config)
        {
            //将配置保存到本地
            path = $"{SerialNo}-config.lb";
            ConfigManager<PHM6000SensorConfig>.SaveConfig<PHM6000SensorConfig>(config, @path);
            SetTargetParam(config);
            //-----------
            int result = 0;
            var type = config.GetType();
            var propLineScan = type.GetProperty(nameof(config.LineScanTriggerSource));
            var val = (EnumLineScanTriggerSource)propLineScan.GetValue(config);
            var props = config.GetType().GetProperties();
            //排除Yè½´
            props = props.Where(d => d.Name != nameof(config.YResolution)).ToArray();
            //排除不需要的项
            if (val == EnumLineScanTriggerSource.固定频率)
            {
                props = props.Where(d => d.Name != nameof(config.EncoderTriggerDirection) && d.Name != nameof(config.EncoderTriggerInterval) && d.Name != nameof(config.EncoderTriggerSignalCountingMode)).ToArray();
            }
            else
            {
                props = props.Where(d => d.Name != nameof(config.SoftwareTriggerRate)).ToArray();
            }
            foreach (var p in props)
            {
                //跳过自定义参数
                var iscustomAttr = p.GetCustomAttribute<IsCustomAttribute>();
                if (iscustomAttr != null) continue;
                //判断是6030传感器还是普通传感器
                if (SerialNo.StartsWith("LX030") && p.Name == nameof(config.AnalogGain))
                {
                    continue;
                }
                if (!SerialNo.StartsWith("LX030") && p.Name == nameof(config.AnalogGainFor6030))
                {
                    continue;
                }
                var id = Convert.ToInt32(Enum.Parse(typeof(EnumNameId), p.Name));
                if (p.PropertyType == typeof(int))
                {
                    var value = Convert.ToInt32(p.GetValue(config));
                    result = PHM6000Profiler.SetProfilerParameter(Entry, id, value, 0, 0);
                }
                else if (p.PropertyType == typeof(float))
                {
                    var value = Convert.ToDouble(p.GetValue(config));
                    result = PHM6000Profiler.SetProfilerParameter(Entry, id, 0, value, 0);
                }
                else
                {
                    var value = Convert.ToInt32(p.GetValue(config));
                    result = PHM6000Profiler.SetProfilerParameter(Entry, id, 0, 0, value);
                    //if (p.Name == nameof(config.AnalogGainFor6030))
                    //{
                    //    var a = value;
                    //}
                }
                if (result == -1)
                {
                    var disattr = p.GetCustomAttribute<DisplayNameAttribute>();
                    var name = disattr?.DisplayName ?? p.Name;
                    throw new Exception($"设置参数{name}时不成功!");
                }
            }
            var finalResult = PHM6000Profiler.SaveAllParametersToDevice(Entry);
            if (finalResult != 0)
            {
                return false;
            }
            return true;
        }
        #endregion
        #region æ–­å¼€ä¼ æ„Ÿå™¨
        public void DisConnectCamera()
        {
            if (IP == "0.0.0.0") return;
            var result = PHM6000Profiler.DisconnectFromCamera(Entry, IP);
            if (result == -1)
            {
                AsyncLogHelper.Error("断开摄像头失败!");
                throw new Exception("断开摄像头失败!");
            }
        }
        public void DestoryCamera()
        {
            if (Entry != IntPtr.Zero)
            {
                PHM6000Profiler.DestroyCameraEntry(Entry);
                Entry = IntPtr.Zero;
            }
            //if (pointPic != IntPtr.Zero)
            //{
            //    PclEntry.ClearPCLPoints(pointPic);
            //    PclEntry.DestroyPCLWindow(pointPic);
            //    pointPic = IntPtr.Zero;
            //}
            if (lightPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(lightPic);
                Pilot2D.DestroyPilot2DEntry(lightPic);
                lightPic = IntPtr.Zero;
            }
            if (outlinePic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(outlinePic);
                Pilot2D.DestroyPilot2DEntry(outlinePic);
                outlinePic = IntPtr.Zero;
            }
            if (outlineMainPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(outlineMainPic);
                Pilot2D.DestroyPilot2DEntry(outlineMainPic);
                outlineMainPic = IntPtr.Zero;
            }
            if (deepPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(deepPic);
                Pilot2D.DestroyPilot2DEntry(deepPic);
                deepPic = IntPtr.Zero;
            }
        }
        public void ClearDatas()
        {
            //if (pointPic != IntPtr.Zero)
            //{
            //    PclEntry.ClearPCLPoints(pointPic);
            //}
            if (lightPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(lightPic);
            }
            if (outlinePic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(outlinePic);
            }
            if (outlineMainPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(outlineMainPic);
            }
            if (deepPic != IntPtr.Zero)
            {
                Pilot2D.ClearAllPoints(deepPic);
            }
        }
        #endregion
        #region å•次采集,启动回调
        public void StartScan()
        {
            if (IP == "0.0.0.0") return;
            lock (_lock)
            {
                LineDatas.Clear();
            }
            int result = PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero);//设置数采回调,注意好像没地方有销毁
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero)设置失败!");
            }
            result = PHM6000Profiler.SetAcquisitionMode(Entry, 1, 0);//设置数采模式
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionMode(Entry, 1, 0)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionMode(Entry, 1, 0)设置失败!");
            }
            result = PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0);//开始采集
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0)设置失败!");
            }
        }
        #endregion
        #region å¯åŠ¨è¿žç»­é‡‡é›†
        public void ContinuousScan()
        {
            if (IP.Equals("0.0.0.0"))
            {
                return;
            }
            lock (_lock)
            {
                LineDatas.Clear();
            }
            int result = PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero);//设置数采回调,注意好像没地方有销毁
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionCallbackZA(Entry, IntPtr.Zero, IntPtr.Zero)设置失败!");
            }
            result = PHM6000Profiler.SetAcquisitionMode(Entry, 1, 1);//设置数采模式
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionMode(Entry, 1, 1)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.SetAcquisitionMode(Entry, 1, 1)设置失败!");
            }
            result = PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0);//开始采集
            if (result == 0)
            {
                AsyncLogHelper.Info("PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0)设置成功!");
            }
            else if (result == -1)
            {
                AsyncLogHelper.Info("PHM6000Profiler.StartAcquisition(Entry, 0, 0, 0.0)设置失败!");
            }
        }
        #endregion
        #region åœæ­¢é‡‡é›†ï¼Œåœæ­¢å›¾ç‰‡æ˜¾ç¤º
        public void StopScan()
        {
            if (IP != "0.0.0.0")
            {
                PHM6000Profiler.StopAcquisition(Entry);
            }
        }
        #endregion
        private void RenderVtk(IntPtr instance)
        {
            // èŽ·å–å½“å‰æŽ§ä»¶å°ºå¯¸
            int width = 800;
            int height = 600;
            // è°ƒç”¨VTK渲染方法
            PclEntry.RenderPCLWindow(pointPic, width, height);
            PclEntry.UpdatePCLPointColors(pointPic, "z");
            PclEntry.ShowCubeAxes(pointPic, 1);
            PclEntry.ShowLookUpTable(pointPic);
            // å¤„理颜色范围
            double fMin = 0, fMax = 0;
            if (PclEntry.GetPointCloudBound(pointPic, ref fMin, ref fMax) != 0)
            {
                PclEntry.SetLookUpTableRange(pointPic, fMin, fMax);
            }
        }
        #region ä¿å­˜lb3d文件
        public void SaveLb3dData(string filePath)
        {
            try
            {
                // ä½¿ç”¨GB2312编码文件名
                Encoding gb2312 = Encoding.GetEncoding("GB2312");
                byte[] encodedBytes = gb2312.GetBytes(filePath);
                //byte[] encodedBytes = Encoding.UTF8.GetBytes(filePath);
                // è°ƒç”¨åŽŸç”Ÿä¿å­˜æ–¹æ³•
                //switch (MainForm.PicModeflg)
                //{
                //    case 0:
                //        int result0 = Pilot2D.SavePicture(lightPic, encodedBytes);
                //        break;
                //    case 1:
                //        int result1 = PclInvoke.SaveDataToFile(Entry, encodedBytes);
                //        break;
                //}
            }
            catch (EncoderFallbackException)
            {
                MessageBox.Show("文件名包含GB2312不支持的字符", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        #endregion
        #region
        // å®šä¹‰å§”托和事件
        public class AcquisitionCompletedEventArgs : EventArgs
        {
            public IntPtr Instance { get; set; }
            public int Option { get; set; }
        }
        // å£°æ˜Žäº‹ä»¶
        public event EventHandler<AcquisitionCompletedEventArgs> AcquisitionCompleted;
        // è§¦å‘事件的方法
        public void OnAcquisitionCompleted(IntPtr pInstance, int nOption)
        {
            if (nOption == 2)
            {
                int width = 800;
                int height = 600;
                // è°ƒç”¨VTK渲染方法
                PclEntry.RenderPCLWindow(pointPic, width, height);
                PclEntry.UpdatePCLPointColors(pointPic, "z");
                PclEntry.ShowCubeAxes(pointPic, 1);
                PclEntry.ShowLookUpTable(pointPic);
                // å¤„理颜色范围
                double fMin = 0, fMax = 0;
                if (PclEntry.GetPointCloudBound(pointPic, ref fMin, ref fMax) != 0)
                {
                    PclEntry.SetLookUpTableRange(pointPic, fMin, fMax);
                }
            }
        }
        #endregion
        //轮廓图标定
        public async Task<float[]> StartOutlineCali(string roiTxt)
        {
            var config = GetConfig();
            PARAM_BAR pARAM_BAR = new PARAM_BAR()
            {
                Height = config.BarHeight,
                Width = config.BarWidth,
                HoleCount = config.BarHoleCount,
                HoleDiameter = config.BarHoleDiameter,
                HoleDistance = config.BarHoleDistance,
                DOF = config.BarDOF,
            };
            SENSOR_POSITION stPosition = new SENSOR_POSITION
            {
                IsReverse = config.IsReverse,
                IsOpposite = config.IsOpposite,
                fStdDistance = config.fStdDistance,
                fXCenter = config.fXCenter,
                x = config.x,
                y = config.y,
                z = config.z,
                xAngle = config.xAngle,
                yAngle = config.yAngle,
                zAngle = config.zAngle
            };
            SysCalibration.SetSensorPosition(CaliEntry, Index, stPosition);
            var roi = GetROICaliThkiness(roiTxt, config);
            SysCalibration.SetLineROI(CaliEntry, Index, roi, false);
            IntPtr lineLastdatas = GetLineLastData();
            await Task.Run(() =>
            {
                bool result = SysCalibration.AlignmentBar(CaliEntry, Index, Constants.TYPE_STATIONARY, pARAM_BAR);
            });
            return new float[] { };
        }
        public async Task StartOutlineDD(string roiTxt)
        {
            var config = GetConfig();
            PARAM_BAR param_bar = new PARAM_BAR()
            {
                Height = config.BarHeight,
                Width = config.BarWidth,
                HoleCount = config.BarHoleCount,
                HoleDiameter = config.BarHoleDiameter,
                HoleDistance = config.BarHoleDistance,
                DOF = config.BarDOF,
            };
            SENSOR_POSITION stPosition = new SENSOR_POSITION
            {
                IsReverse = config.IsReverse,
                IsOpposite = config.IsOpposite,
                fStdDistance = config.fStdDistance,
                fXCenter = config.fXCenter,
                x = config.x,
                y = config.y,
                z = config.z,
                xAngle = config.xAngle,
                yAngle = config.yAngle,
                zAngle = config.zAngle
            };
            SysCalibration.SetSensorPosition(CaliEntry, Index, stPosition);
            var roi = GetROICaliThkiness(roiTxt, config);
            SysCalibration.SetLineROI(CaliEntry, Index, roi, false);
            IntPtr lineLastdatas = GetLineLastData();
            //var linedata = linedatas[linedatas.Count - 1];
            //var ptr = Marshal.AllocHGlobal(linedata.Length);
            //Marshal.Copy(linedata, 0, ptr, linedata.Length);
            //Marshal.FreeHGlobal(lineLastdatas);
            //await Task.Run(() =>
            //{
            //    bool result = SysCalibration.AlignmentBar(CaliEntry, Index, SysCalibration.TYPE_STATIONARY, pARAM_BAR);
            //});
        }
        public async Task<float> MeasureDistanceOutLine()
        {
            var config = GetConfig();
            SENSOR_POSITION sENSOR_POSITION = new SENSOR_POSITION
            {
                IsReverse = config.IsReverse,
                IsOpposite = config.IsOpposite,
                fStdDistance = config.fStdDistance,
                fXCenter = config.fXCenter,
                x = config.x,
                y = config.y,
                z = config.z,
                xAngle = config.xAngle,
                yAngle = config.yAngle,
                zAngle = config.zAngle
            };
            SysCalibration.SetSensorPosition(CaliEntry, Index, sENSOR_POSITION);//设置传感器位置
            SysCalibration.SetRate(CaliEntry, Index, config.XAxisResolution / 1000, config.YResolution / 1000);
            SysCalibration.ClearData(CaliEntry, Index);//清除以前数据
            var r = await Task.Run<float>(() =>
            {
                //输入新数据
                unsafe
                {
                    IntPtr pdata = IntPtr.Zero;
                    if (sline + eline != 0 && eline > sline)
                    {
                        for (ulong i = sline; i < eline; i++)
                        {
                            bool useEncoder = false;
                            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                            pdata = PHM6000Profiler.GetLineDataByIndex(Entry, i);
                            if (pdata == IntPtr.Zero)
                                break;
                            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                        }
                    }
                    else
                    {
                        ulong nindex = 0;
                        while ((pdata = PHM6000Profiler.GetLineDataByIndex(Entry, nindex)) != IntPtr.Zero)
                        {
                            bool useEncoder = false;
                            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                            nindex++;
                        }
                    }
                }
                SetTargetParam(config);//设置目标测量参数
                //var result = SysCalibration.MeasureDistance(CaliEntry);
                float measuredValue = SysCalibration.MeasureTargetHigh(CaliEntry, Index);
                var result = (float)Math.Round(measuredValue, 3);
                return result;
            });
            return r;
        }
        public async Task<float[,]> MeasureOutLine​Thickness​()
        {
            var result = await Task.Run(() =>
            {
                var config = GetConfig();
                SetTargetParam(config);//设置目标测量参数
                float[,] datas = new float[config.nPartitionX, config.nPartitionY];
                data = new float[config.nPartitionX * config.nPartitionY];
                int number = 0;
                for (int i = 0; i < config.nPartitionX; i++)
                {
                    for (int j = 0; j < config.nPartitionY; j++)
                    {
                        number++;
                        float measuredValue = SysCalibration.MeasureRoiHigh(CaliEntry, Index, number);
                        // ä¿ç•™3位小数
                        datas[i, j] = (float)Math.Round(measuredValue, 3);
                    }
                }
                //lBCMap = SysCalibration.GetDepthMap(CaliEntry, Index, 4);
                return datas;
            });
            return result;
        }
        //二维图标定
        public async Task StartLiaghtAndDeepCali(CaliModel caliModel)
        {
            //LBLineDataZA lBLineDataZA = new LBLineDataZA();
            SENSOR_POSITION sENSOR_POSITION = new SENSOR_POSITION
            {
                IsReverse = caliModel.IsReverse,
                IsOpposite = caliModel.IsOpposite,
                fStdDistance = caliModel.fStdDistance,
                fXCenter = caliModel.fXCenter,
                x = caliModel.x,
                y = caliModel.y,
                z = caliModel.z,
                xAngle = caliModel.xAngle,
                yAngle = caliModel.yAngle,
                zAngle = caliModel.zAngle,
            };
            var config = GetConfig();
            PARAM_BOARD pARAM_BOARD = new PARAM_BOARD()
            {
                //Height = config.Height,
                //Width = config.Width,
                //HoleDiameter = config.HoleDiameter,
                //HoleDistance = config.HoleDistance,
                //LocationHoleX1 = config.LocationHoleX1,
                //LocationHoleX2 = config.LocationHoleX2,
                //LocationHoleY1 = config.LocationHoleY1,
                //LocationHoleY2 = config.LocationHoleY2,
            };
            SysCalibration.SetSensorPosition(CaliEntry, Index, sENSOR_POSITION);//设置传感器位置
            var roi = caliModel.Plane.Split(',');
            var roi1 = GetROI(caliModel.Plane, config);
            var roi2 = GetROI(caliModel.Hole1, config);
            var roi3 = GetROI(caliModel.Hole2, config);
            var roi4 = GetROI(caliModel.Hole3, config);
            SysCalibration.SetRate(CaliEntry, Index, config.XAxisResolution / 1000, config.YResolution / 1000);
            SysCalibration.SetFlatROI(CaliEntry, Index, roi1, true);
            SysCalibration.SetHoleROI(CaliEntry, Index, 0, roi2, true);
            SysCalibration.SetHoleROI(CaliEntry, Index, 1, roi3, true);
            SysCalibration.SetHoleROI(CaliEntry, Index, 2, roi4, true);
            SysCalibration.SetBoardParameter(CaliEntry, pARAM_BOARD);
            SysCalibration.ClearData(CaliEntry, Index);//清除以前数据
            await Task.Run(() =>
            {
                //修改此段代码
                //foreach (var item in GetLineDatas())
                unsafe
                {
                    IntPtr pdata = IntPtr.Zero;
                    //if (sline + eline != 0 && eline > sline)
                    //{
                    //    for (ulong i = sline; i < eline; i++)
                    //    {
                    //        bool useEncoder = false;
                    //        if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                    //        //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                    //        pdata = GetLineDataByIndex(Entry, i);
                    //        if (pdata == IntPtr.Zero)
                    //            break;
                    //        SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                    //    }
                    //}
                    //else
                    {
                        ulong nindex = 0;
                        while ((pdata = PHM6000Profiler.GetLineDataByIndex(Entry, nindex)) != IntPtr.Zero)
                        {
                            bool useEncoder = false;
                            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                            nindex++;
                        }
                    }
                }
                SysCalibration.AlignmentMovingFlat(CaliEntry, Index);//下次打开程序时可能会序号错误
                //SysCalibration.SystemCalibration(caliEntry);//error没有真实的孔,就会卡进程
            });
        }
        //测量厚度
        public async Task<float> MeasureDistance()
        {
            var config = GetConfig();
            SENSOR_POSITION sENSOR_POSITION = new SENSOR_POSITION
            {
                //IsReverse = CaliModel.IsReverse,
                //IsOpposite = CaliModel.IsOpposite,
                //fStdDistance = CaliModel.fStdDistance,
                //fXCenter = CaliModel.fXCenter,
                //x = CaliModel.x,
                //y = CaliModel.y,
                //z = CaliModel.z,
                //xAngle = CaliModel.xAngle,
                //yAngle = CaliModel.yAngle,
                //zAngle = CaliModel.zAngle,
            };
            SysCalibration.SetSensorPosition(CaliEntry, Index, sENSOR_POSITION);//设置传感器位置
            SysCalibration.SetRate(CaliEntry, Index, config.XAxisResolution / 1000, config.YResolution / 1000);
            SysCalibration.ClearData(CaliEntry, Index);//清除以前数据
            var r = await Task.Run<float>(() =>
            {
                //输入新数据
                unsafe
                {
                    IntPtr pdata = IntPtr.Zero;
                    if (sline + eline != 0 && eline > sline)
                    {
                        for (ulong i = sline; i < eline; i++)
                        {
                            bool useEncoder = false;
                            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                            pdata = PHM6000Profiler.GetLineDataByIndex(Entry, i);
                            if (pdata == IntPtr.Zero)
                                break;
                            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                        }
                    }
                    else
                    {
                        ulong nindex = 0;
                        while ((pdata = PHM6000Profiler.GetLineDataByIndex(Entry, nindex)) != IntPtr.Zero)
                        {
                            bool useEncoder = false;
                            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                            nindex++;
                        }
                    }
                }
                SetTargetParam(config);//设置目标测量参数
                //var result = SysCalibration.MeasureDistance(CaliEntry);
                float measuredValue = SysCalibration.MeasureTargetHigh(CaliEntry, Index);
                var result = (float)Math.Round(measuredValue, 3);
                return result;
            });
            return r;
        }
        public static ulong sline = 0;
        public static ulong eline = 0;
        public static IntPtr lBCMap = IntPtr.Zero;
        public static float[] data = null;
        //测量凹凸
        public async Task<float[,]> Measure​Uneven​()
        {
            var result = await Task.Run(() =>
            {
                var config = GetConfig();
                //SENSOR_POSITION sENSOR_POSITION = new SENSOR_POSITION
                //{
                //    IsReverse = CaliModel.IsReverse,
                //    IsOpposite = CaliModel.IsOpposite,
                //    fStdDistance = CaliModel.fStdDistance,
                //    fXCenter = CaliModel.fXCenter,
                //    x = CaliModel.x,
                //    y = CaliModel.y,
                //    z = CaliModel.z,
                //    xAngle = CaliModel.xAngle,
                //    yAngle = CaliModel.yAngle,
                //    zAngle = CaliModel.zAngle,
                //};
                //SysCalibration.SetSensorPosition(CaliEntry, Index, sENSOR_POSITION);//设置传感器位置
                //SysCalibration.SetRate(CaliEntry, Index, config.XAxisResolution / 1000, config.YResolution / 1000);
                //SysCalibration.ClearData(CaliEntry, Index);//清除以前数据
                ////输入新数据
                //unsafe
                //{
                //    IntPtr pdata = IntPtr.Zero;
                //    if (sline + eline != 0 && eline > sline)
                //    {
                //        for (ulong i = sline; i < eline; i++)
                //        {
                //            bool useEncoder = false;
                //            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                //            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                //            pdata = GetLineDataByIndex(Entry, i);
                //            if (pdata == IntPtr.Zero)
                //                break;
                //            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                //        }
                //    }
                //    else
                //    {
                //        ulong nindex = 0;
                //        while ((pdata = GetLineDataByIndex(Entry, nindex)) != IntPtr.Zero)
                //        {
                //            bool useEncoder = false;
                //            if (config.LineScanTriggerSource == EnumLineScanTriggerSource.编码器) useEncoder = true;
                //            //使用了引用,什么时候完成使用?如果长时间,代码会有内存风险
                //            SysCalibration.AddLineDataArray(CaliEntry, Index, pdata, useEncoder, 1);//最后个参数是什么意思
                //            nindex++;
                //        }
                //    }
                //}
                SetTargetParam(config);//设置目标测量参数
                float[,] datas = new float[config.nPartitionX, config.nPartitionY];
                data = new float[config.nPartitionX * config.nPartitionY];
                int number = 0;
                for (int i = 0; i < config.nPartitionX; i++)
                {
                    for (int j = 0; j < config.nPartitionY; j++)
                    {
                        number++;
                        float measuredValue = SysCalibration.MeasureRoiHigh(CaliEntry, Index, number);
                        // ä¿ç•™3位小数
                        datas[i, j] = (float)Math.Round(measuredValue, 3);
                    }
                }
                //lBCMap = SysCalibration.GetDepthMap(CaliEntry, Index, 4);
                return datas;
            });
            return result;
        }
        LB_ROI GetROI(string s, PHM6000SensorConfig config)
        {
            var roi = s.Split(',');
            LB_ROI lB_ROI = new LB_ROI()
            {
                left = Convert.ToInt32(roi[0]) * config.XAxisResolution / 1000,
                top = Convert.ToInt32(roi[1]) * config.YResolution / 1000,
                right = Convert.ToInt32(roi[2]) * config.XAxisResolution / 1000,
                bottom = Convert.ToInt32(roi[3]) * config.YResolution / 1000,
                //    left = Convert.ToInt32(roi[0]) * 4096 / 2048,
                //    top = (int)(325.0 - 225.0 - float.Parse(roi[1]) * (470.0 - 225.0) / (1024.0 - 1.0) + 0.5),
                //    right = Convert.ToInt32(roi[2]) * 4096 / 2048,
                //    bottom = (int)(325.0 - 225.0 - float.Parse(roi[3]) * (470.0 - 225.0) / (1024.0 - 1.0) + 0.5),
                //};
                //float fTemp;
                //if (lB_ROI.left > lB_ROI.right)
                //{
                //    fTemp = lB_ROI.left;
                //    lB_ROI.left = lB_ROI.right;
                //    lB_ROI.right = fTemp;
                //}
                //if (lB_ROI.top > lB_ROI.bottom)
                //{
                //    fTemp = lB_ROI.top;
                //    lB_ROI.top = lB_ROI.bottom;
                //    lB_ROI.bottom = fTemp;
                //}
            };
            return lB_ROI;
        }
        LB_ROI GetROICaliThkiness(string s, PHM6000SensorConfig config)
        {
            var roi = s.Split(',');
            LB_ROI lB_ROI = new LB_ROI()
            {
                //left = Convert.ToInt32(roi[0]) * config.XAxisResolution / 1000,
                //top = Convert.ToInt32(roi[1]) * config.YResolution / 1000,
                //right = Convert.ToInt32(roi[2]) * config.XAxisResolution / 1000,
                //bottom = Convert.ToInt32(roi[3]) * config.YResolution / 1000,
                left = Convert.ToInt32(roi[0]) * 4096 / 2048,
                top = (int)(325.0 - 225.0 - float.Parse(roi[1]) * (470.0 - 225.0) / (1024.0 - 1.0) + 0.5),
                right = Convert.ToInt32(roi[2]) * 4096 / 2048,
                bottom = (int)(325.0 - 225.0 - float.Parse(roi[3]) * (470.0 - 225.0) / (1024.0 - 1.0) + 0.5),
            };
            float fTemp;
            if (lB_ROI.left > lB_ROI.right)
            {
                fTemp = lB_ROI.left;
                lB_ROI.left = lB_ROI.right;
                lB_ROI.right = fTemp;
            }
            if (lB_ROI.top > lB_ROI.bottom)
            {
                fTemp = lB_ROI.top;
                lB_ROI.top = lB_ROI.bottom;
                lB_ROI.bottom = fTemp;
            }
            return lB_ROI;
        }
    }
    #region ä¼ æ„Ÿå™¨åˆ—表模型类
    /// <summary>
    /// PHM6000SensorModel
    /// </summary>
    [JsonObject(MemberSerialization.OptOut)]
    [TypeConverter(typeof(PropertySorter))]
    public class PHM6000SensorModel
    {
        /// <summary>
        /// IP地址
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(2)]
        [DisplayName("IP地址")]
        [Browsable(true)]
        public string IP { get; set; }
        /// <summary>
        /// ç«¯å£
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(3)]
        [DisplayName("端口")]
        [Browsable(true)]
        public int Port { get; set; }
        /// <summary>
        /// åºåˆ—号
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(1)]
        [DisplayName("序列号")]
        [Browsable(true)]
        public string SerialNo { get; set; }
        /// <summary>
        /// çŠ¶æ€
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(0)]
        [DisplayName("状态")]
        [Browsable(true)]
        public string State { get; set; }
        /// <summary>
        /// PHM6000Sensor
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(4)]
        [Browsable(false)]
        public PHM6000Sensor Sensor { get; set; }
        /// <summary>
        /// Model
        /// </summary>
        [Category("PHM6000SensorModel"), PropertyOrder(5)]
        [Browsable(false)]
        public string Model { get; set; }
    }
    #endregion
    //采集数据时要显示的图类形
    public enum EnumFetchPicType
    {
        light, deep, pointCloud, outline, mainOutLine
    }
    public class FloatArrayToIntPtrConverter
    {
        public unsafe static IntPtr ConvertFloatArrayToIntPtr(float[] data)
        {
            if (data == null || data.Length == 0)
            {
                return IntPtr.Zero;
            }
            fixed (float* p = data)
            {
                return (IntPtr)p;
            }
        }
    }
}
在上述文件截断后对比
LB_SmartVisionCameraDevice/PHM6000/PHM6000SensorConfig.cs LB_SmartVisionCameraDevice/SensorManager.cs LB_SmartVisionCameraDevice/ref/PHM6000.dll LB_SmartVisionCameraDevice/ref/PHM6000API.dll LB_SmartVisionCameraDevice/ref/PHM6000API.lib LB_SmartVisionCameraDevice/ref/Pilot2D.dll LB_SmartVisionCameraDevice/ref/PointCloud3D.dll LB_SmartVisionCameraSDK/LB_SmartVisionCameraSDK.csproj LB_SmartVisionCameraSDK/PHM6000/PHM6000Profiler.cs LB_SmartVisionCameraSDK/PHM6000/Pilot2D.cs LB_SmartVisionCameraSDK/PHM6000/Point.cs LB_SmartVisionCameraSDK/PHM6000/ProfilerData.cs LB_SmartVisionCameraSDK/PHM6000/SysCalibration.cs LB_SmartVisionCameraSDK/PclEntry.cs LB_SmartVisionCameraSDK/ref/PHM6000.dll LB_SmartVisionCameraSDK/ref/PHM6000API.dll LB_SmartVisionCameraSDK/ref/PHM6000API.lib LB_SmartVisionCameraSDK/ref/Pilot2D.dll LB_SmartVisionCameraSDK/ref/PointCloud3D.dll LB_SmartVisionCommon/AESHelper.cs LB_SmartVisionCommon/AsyncLogHelper.cs LB_SmartVisionCommon/CommonVar.cs LB_SmartVisionCommon/ConfigManager.cs LB_SmartVisionCommon/DiskInfoHelper.cs LB_SmartVisionCommon/DynamicPermissionObject.cs LB_SmartVisionCommon/DynamicPropertyDescriptor.cs LB_SmartVisionCommon/Fun.cs LB_SmartVisionCommon/LB_SmartVisionCommon.csproj LB_SmartVisionCommon/LogHelper.cs LB_SmartVisionCommon/NetworkDiagnostics.cs LB_SmartVisionCommon/NetworkMonitor.cs LB_SmartVisionCommon/NetworkTester.cs LB_SmartVisionCommon/PermissionAttribute.cs LB_SmartVisionCommon/PermissionPropertyDescriptor.cs LB_SmartVisionCommon/PropertySorter.cs LB_SmartVisionCommon/UserData.cs LB_SmartVisionCommon/UserManager.cs LB_SmartVisionLoginUI/App.config LB_SmartVisionLoginUI/App.xaml LB_SmartVisionLoginUI/App.xaml.cs LB_SmartVisionLoginUI/AssemblyInfo.cs LB_SmartVisionLoginUI/ICommonData_Loading.cs LB_SmartVisionLoginUI/LB_SmartVisionLoginUI.csproj LB_SmartVisionLoginUI/MainWindow.xaml LB_SmartVisionLoginUI/MainWindow.xaml.cs LB_SmartVisionLoginUI/favicon.ico LB_SmartVisionLoginUI/images/01.JPG LB_SmartVisionLoginUI/images/02.png LB_SmartVisionLoginUI/images/03.png LB_SmartVisionLoginUI/images/04.png LB_SmartVisionLoginUI/images/05.png LB_SmartVisionLoginUI/images/06.png LB_SmartVisionLoginUI/images/07.png LB_SmartVisionLoginUI/images/favicon.ico LB_SmartVisionLoginUI/images/lanbao.jpg LB_SmartVisionLoginUI/images/logo.ico LB_SmartVisionLoginUI/images/logo_h.png LB_SmartVisionLoginUI/images/键盘.ico LB_SmartVisionLoginUI/lanbao.jpg LB_SmartVisionLoginUI/logo.ico LB_SmartVisionLoginUI/logo_h.png LB_VisionControl/Form1.Designer.cs LB_VisionControl/Form1.cs LB_VisionControl/Form1.resx LB_VisionControl/Forms/RenameForm.Designer.cs LB_VisionControl/Forms/RenameForm.cs LB_VisionControl/Forms/RenameForm.resx LB_VisionControl/LB_VisionControl.csproj LB_VisionControl/Program.cs LB_VisionControl/Properties/Resources.Designer.cs LB_VisionControl/Properties/Resources.resx LB_VisionControl/ROI.cs LB_VisionControl/ScriptEditControl/ClassFileList.Designer.cs LB_VisionControl/ScriptEditControl/ClassFileList.cs LB_VisionControl/ScriptEditControl/ClassFileList.resx LB_VisionControl/ScriptEditControl/CommConfig.cs LB_VisionControl/ScriptEditControl/CommandRun.cs LB_VisionControl/ScriptEditControl/CompliReslut.cs LB_VisionControl/ScriptEditControl/ComplieBuilder.cs LB_VisionControl/ScriptEditControl/ComplieType.cs LB_VisionControl/ScriptEditControl/ComplieUI.Designer.cs LB_VisionControl/ScriptEditControl/ComplieUI.cs LB_VisionControl/ScriptEditControl/ComplieUI.resx LB_VisionControl/ScriptEditControl/ConsoleTextBox.cs LB_VisionControl/ScriptEditControl/ConsoleTextBox.resx LB_VisionControl/ScriptEditControl/ContextMenuStripEx.cs LB_VisionControl/ScriptEditControl/EditHeightLight.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/AutocompleteItem.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/AutocompleteMenu.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Char.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/CommandManager.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Commands.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Export.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.Designer.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FastColoredTextBox.resx LB_VisionControl/ScriptEditControl/FastColorTextBox/FileTextSource.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.Designer.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/FindForm.resx LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.Designer.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/GoToForm.resx LB_VisionControl/ScriptEditControl/FastColorTextBox/LimitedStack.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Line.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/LinesAccessor.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Place.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/PlatformType.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/Range.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.Designer.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/ReplaceForm.resx LB_VisionControl/ScriptEditControl/FastColorTextBox/Style.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/SyntaxDescriptor.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/SyntaxHighlighter.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/TextSource.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/TypeDescriptor.cs LB_VisionControl/ScriptEditControl/FastColorTextBox/VisualMarker.cs.cs LB_VisionControl/ScriptEditControl/KeyWordsAuto.cs LB_VisionControl/ScriptEditControl/KeysWordCMDAuto.cs LB_VisionControl/ScriptEditControl/ScriptEditControl.Designer.cs LB_VisionControl/ScriptEditControl/ScriptEditControl.cs LB_VisionControl/ScriptEditControl/ScriptEditControl.resx LB_VisionControl/ScriptEditControl/ScriptEditForm.Designer.cs LB_VisionControl/ScriptEditControl/ScriptEditForm.cs LB_VisionControl/ScriptEditControl/ScriptEditForm.resx LB_VisionControl/ScriptEditControl/csharp.ico LB_VisionControl/UserHSmartWindowControl.Designer.cs LB_VisionControl/UserHSmartWindowControl.cs LB_VisionControl/UserHSmartWindowControl.resx LB_VisionControl/UserItem.Designer.cs LB_VisionControl/UserItem.cs LB_VisionControl/UserItem.resx LB_VisionControl/UserPictureBox.cs LB_VisionControl/ref/halcondotnet.dll LB_VisionFlowNode/FlowConnection.cs LB_VisionFlowNode/FlowEnum.cs LB_VisionFlowNode/FlowNode.cs LB_VisionFlowNode/FlowNodeEditor.Designer.cs LB_VisionFlowNode/FlowNodeEditor.cs LB_VisionFlowNode/FlowNodeEditor.resx LB_VisionFlowNode/FlowPanel.cs LB_VisionFlowNode/FlowSerializer.cs LB_VisionFlowNode/IFlowContext.cs LB_VisionFlowNode/LB_VisionFlowNode.csproj LB_VisionFlowNode/MainForm.Designer.cs LB_VisionFlowNode/MainForm.cs LB_VisionFlowNode/MainForm.resx LB_VisionFlowNode/Program.cs LB_VisionFlowNode/RenameForm.Designer.cs LB_VisionFlowNode/RenameForm.cs LB_VisionFlowNode/RenameForm.resx LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithm.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.Designer.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TAlgorithmEdit.resx LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestTool.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.cs LB_VisionProcesses/Alogrithms/BaseAlgorithm/TestTool/TestToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobTool.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HBlobTool/HBlobToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HCalibTool/BaseCalib.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HCalibTool/HCaltab.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dTool.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindCode2dTool/HFindCode2dToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineTool.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindLineTool/HFindLineToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelTool.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindModelTool/HFindModelToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelTool.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HFindMultiModelToolEdit.resx LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.Designer.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.cs LB_VisionProcesses/Alogrithms/Halcon/2D/HFindMultiModelTool/HMulitModelControl.resx LB_VisionProcesses/Alogrithms/Halcon/HDevelopExport.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobTool.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/BlobTool/BlobToolEdit.resx LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineTool.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindLineTool/FindLineToolEdit.resx LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelTool.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.Designer.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.cs LB_VisionProcesses/Alogrithms/OpenCvSharp/FindModelTool/FindModelToolEdit.resx LB_VisionProcesses/Cameras/2DCameraForm.Designer.cs LB_VisionProcesses/Cameras/2DCameraForm.cs LB_VisionProcesses/Cameras/2DCameraForm.resx LB_VisionProcesses/Cameras/BaseCamera.cs LB_VisionProcesses/Cameras/CameraConfig.cs LB_VisionProcesses/Cameras/ICamera.cs LB_VisionProcesses/Communicators/BaseCommunicator.cs LB_VisionProcesses/Communicators/CommunicatorCollections.cs LB_VisionProcesses/Communicators/CommunicatorConfig.cs LB_VisionProcesses/Communicators/CommunicatorForm.Designer.cs LB_VisionProcesses/Communicators/CommunicatorForm.cs LB_VisionProcesses/Communicators/CommunicatorForm.resx LB_VisionProcesses/Communicators/ICommunicator.cs LB_VisionProcesses/Communicators/TCom/LocalMonitor.cs LB_VisionProcesses/Communicators/TCom/TCPClient.cs LB_VisionProcesses/Communicators/TCom/TCPServer.cs LB_VisionProcesses/Communicators/TCom/UARTPort.cs LB_VisionProcesses/Communicators/UserCommunicator/T306Command/T306CommandTool.cs LB_VisionProcesses/Forms/GlobalVarControl.Designer.cs LB_VisionProcesses/Forms/GlobalVarControl.cs LB_VisionProcesses/Forms/GlobalVarControl.resx LB_VisionProcesses/Forms/GlobalVarForm.Designer.cs LB_VisionProcesses/Forms/GlobalVarForm.cs LB_VisionProcesses/Forms/GlobalVarForm.resx LB_VisionProcesses/IProcess.cs LB_VisionProcesses/LB_VisionProcesses.csproj LB_VisionProcesses/MainForm.Designer.cs LB_VisionProcesses/MainForm.cs LB_VisionProcesses/MainForm.resx LB_VisionProcesses/PluginInfo.cs LB_VisionProcesses/PluginLoadContext.cs LB_VisionProcesses/PluginManager.cs LB_VisionProcesses/ProcessAttribute.cs LB_VisionProcesses/ProcessCollections.cs LB_VisionProcesses/ProcessEditForm.Designer.cs LB_VisionProcesses/ProcessEditForm.cs LB_VisionProcesses/ProcessEditForm.resx LB_VisionProcesses/ProcessInfo.cs LB_VisionProcesses/ProcessParams.cs LB_VisionProcesses/Processes/BaseProcess.cs LB_VisionProcesses/Processes/DelayTime.cs LB_VisionProcesses/Processes/RecordTool/RecordTool.cs LB_VisionProcesses/Processes/ScriptTool/ScriptTool.cs LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.Designer.cs LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.cs LB_VisionProcesses/Processes/ScriptTool/ScriptToolEdit.resx LB_VisionProcesses/Program.cs LB_VisionProcesses/Properties/Resources.Designer.cs LB_VisionProcesses/Properties/Resources.resx LB_VisionProcesses/logo.ico LB_VisionProcesses/ref/CLIDelegate.dll LB_VisionProcesses/ref/MVSDK_Net.XML LB_VisionProcesses/ref/MVSDK_Net.dll LB_VisionProcesses/ref/PHM6000.dll LB_VisionProcesses/ref/PHM6000API.dll LB_VisionProcesses/ref/PHM6000API.lib LB_VisionProcesses/ref/Pilot2D.dll LB_VisionProcesses/ref/PointCloud3D.dll LB_VisionProcesses/ref/ThridLibray.dll LB_VisionProcesses/ref/halcondotnet.dll