src/Bro.Common.Device/DeviceBase/MotionCardBase.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.Device.GTSCard/GTSCardDriver.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.Device.Gocator/GocatorDriver.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.M071.DBManager/ExcelExportHelper.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.M071.Process/M071Process.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.M071.Process/M071Process_MotionCard.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/Bro.UI.Config/MainFrm.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/Bro.Common.Device/DeviceBase/MotionCardBase.cs
@@ -131,7 +131,7 @@ /// <summary> /// 恢复立即暂停 /// </summary> public abstract void ResetImmediatePause(); public abstract void ResetImmediatePause(bool isResumeMoving); #endregion } src/Bro.Device.GTSCard/GTSCardDriver.cs
@@ -46,6 +46,8 @@ /// 运动轴立即暂停 /// </summary> Dictionary<int, ManualResetEvent> axisImmediatePauseHandleDict = new Dictionary<int, ManualResetEvent>(); Dictionary<int, bool> axisImmediatePauseFlag = new Dictionary<int, bool>(); Dictionary<int, bool> axisPauseResumeFlag = new Dictionary<int, bool>(); //Dictionary<int, CancellationTokenSource> axisMoveCancelDict = new Dictionary<int, CancellationTokenSource>(); @@ -145,8 +147,13 @@ { foreach (var preCheck in operationSet.PreCheckIOCollection) { int timeout = operationSet.PreCheckIOTimeout; _pauseHandle.Wait(); IOValue? ioData = null; if (CurrentState == DeviceState.DSOpen) { int timeout = operationSet.PreCheckIOTimeout; while (CurrentState == DeviceState.DSOpen) { Thread.Sleep(10); @@ -155,6 +162,7 @@ if (preCheck.CheckValue == ioData || (operationSet.PreCheckIOTimeout > 0 && timeout < 0)) { break; } } } @@ -170,10 +178,15 @@ // 2.板卡运动 if (CurrentState == DeviceState.DSOpen) { _pauseHandle.Wait(); if (CurrentState == DeviceState.DSOpen) { responseMessage = MoveToPoint(new MotionOperationCollection() { MovingOps = operationSet.MovingOps }); if (!responseMessage.Result) { return responseMessage; } } } @@ -181,7 +194,12 @@ // 3.IO输出 不需要超时 if (CurrentState == DeviceState.DSOpen) { foreach (var ioOutput in operationSet.IOOutputCollection) { _pauseHandle.Wait(); if (CurrentState == DeviceState.DSOpen) { WriteOutput((short)ioOutput.IOItem.IONum, ioOutput.CheckValue); @@ -193,6 +211,7 @@ // responseMessage.Message = $"IO输出不通过,配置:{ioOutput.GetDisplayText()},当前值:{ioData}"; // return responseMessage; //} } } } @@ -228,6 +247,8 @@ #endregion #region ImmediatePause ManualResetEventSlim _pauseHandle = new ManualResetEventSlim(true); /// <summary> /// 启动立即暂停 /// </summary> @@ -236,12 +257,11 @@ if (!_isResetting) { var immediatePauseAxis = IConfig.AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList(); _pauseHandle.Reset(); immediatePauseAxis.ForEach(async axisIndex => { axisImmediatePauseHandleDict[axisIndex].Reset(); //axisMoveCancelDict[axisIndex].Cancel(); axisImmediatePauseFlag[axisIndex] = true; await MoveStop(axisIndex, 0);//所有轴都暂停 }); @@ -251,15 +271,22 @@ /// <summary> /// 恢复立即暂停 /// </summary> public override void ResetImmediatePause() public override void ResetImmediatePause(bool isResumeMoving) { var immediatePauseAxis = IConfig.AxisSettings.FindAll(a => a.IsAxisEnabled && a.IsImmediatePause).Select(u => u.AxisIndex).ToList(); _pauseHandle.Set(); immediatePauseAxis.ForEach(axisIndex => { //axisMoveCancelDict[axisIndex] = new CancellationTokenSource(); axisImmediatePauseFlag[axisIndex] = false; axisImmediatePauseHandleDict[axisIndex].Set(); if (isResumeMoving) { axisPauseResumeFlag[axisIndex] = true; } else { axisPauseResumeFlag[axisIndex] = false; } }); } #endregion @@ -347,19 +374,11 @@ ResponseMessage responseMessage = new ResponseMessage(); if (opConfig is MotionOperationCollection gtsOperationCollection) { //List<Task<bool>> taskList = new List<Task<bool>>(); //foreach (var movingOp in gtsOperationCollection.MovingOps) //{ // var task = SingleAxisMoving(movingOp); // taskList.Add(task); // task.Start(); //} //Task.WaitAll(taskList.ToArray()); //responseMessage.Result = taskList.All(u => u.GetAwaiter().GetResult()); List<bool> resultList = new List<bool>(); Parallel.ForEach(gtsOperationCollection.MovingOps, movingOp => { axisImmediatePauseFlag[movingOp.AxisIndex] = false; axisPauseResumeFlag[movingOp.AxisIndex] = true; resultList.Add(SingleAxisMoving(movingOp).Result); }); responseMessage.Result = resultList.All(u => u == true); @@ -419,16 +438,19 @@ { return Task.Run(() => { axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne(); bool isSuccessAndStop = false; do { axisImmediatePauseHandleDict[optionPara.AxisIndex].WaitOne(); if (!axisPauseResumeFlag[optionPara.AxisIndex]) return true; try { if (IConfig.AxisSettings.FirstOrDefault(a => a.AxisIndex == optionPara.AxisIndex)?.IsAxisEnabled ?? false) { // string _position = ""; string motionType = optionPara.MoveMode == EnumHelper.MotionMode.Normal ? (optionPara.IsAbsolute ? "Abs" : "Rel") : optionPara.MoveMode.ToString(); // _position = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff},{optionPara.AxisIndex},{motionType},{GetPosition(optionPara.AxisIndex)},{GetPrfPosition(optionPara.AxisIndex)},{optionPara.Destination},"; switch (optionPara.MoveMode) { @@ -444,10 +466,10 @@ { isSuccessAndStop = P2PMoveAbs(optionPara); } else { isSuccessAndStop = P2PMoveRel(optionPara); } //else //{ // isSuccessAndStop = P2PMoveRel(optionPara); //} } break; @@ -463,9 +485,6 @@ } break; } //_position += $"{GetPosition(optionPara.AxisIndex)},"; //_position += $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}"; //LogAsync(DateTime.Now, "", _position); } } catch (Exception ex) @@ -473,6 +492,7 @@ isSuccessAndStop = false; LogAsync(DateTime.Now, $"轴{optionPara.AxisIndex}运动异常", ex.GetExceptionMessage()); } } while (axisImmediatePauseFlag[optionPara.AxisIndex]); return isSuccessAndStop; }); } @@ -1282,10 +1302,16 @@ int axis_sts; var axisSettings = IConfig.AxisSettings.FindAll(u => u.IsAxisEnabled); ClearStatus(1, axisSettings.Count); if (AxisStatusList.Count == 0) { Thread.Sleep(10); } foreach (var axisSetting in axisSettings) { //axis_sts = GetAxisStatus((short)axisSetting.AxisIndex); axis_sts = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex).AxisStatus; axis_sts = AxisStatusList.FirstOrDefault(u => u.AxisIndex == axisSetting.AxisIndex)?.AxisStatus ?? 0; if ((axis_sts & 0x200) == 0) { var rst = GTSCardAPI.GT_AxisOn((short)IConfig.CardNum, (short)axisSetting.AxisIndex); src/Bro.Device.Gocator/GocatorDriver.cs
@@ -110,8 +110,6 @@ { imgSet.HImage = new HImage(); imgSet.HImage.GenImage1("uint2", (int)width, zoomHeight, zoomPtr); //imgSet.HImage = imgSet.HImage.ZoomImageSize((int)width, zoomHeight, "constant"); imgSet.HImage_2 = new HImage(); imgSet.HImage_2.GenImage1("uint2", (int)width, zoomHeight, zoomPtr); src/Bro.M071.DBManager/ExcelExportHelper.cs
@@ -107,7 +107,7 @@ { // autofit width of cells with small content ExcelRange columnCells = workSheet.Cells[workSheet.Dimension.Start.Row, columnIndex, workSheet.Dimension.End.Row, columnIndex]; int maxLength = columnCells.Max(cell => cell.Value.ToString().Count()); int maxLength = columnCells.Max(cell => (cell.Value ?? "").ToString().Count()); if (maxLength < 150) { workSheet.Column(columnIndex).AutoFit(); @@ -258,7 +258,7 @@ { try { return obj.ToString(); return (obj ?? "").ToString(); } catch (Exception) { src/Bro.M071.Process/M071Process.cs
@@ -61,7 +61,6 @@ Reset(null, null, null); FullReset(null); } private void InitialMotionCardBaseAxisAlarm() @@ -82,7 +81,7 @@ private void InitialSetting() { //数据库迁移检查 DatabaseInitialize.Initialize(); //DatabaseInitialize.Initialize(); MotionCardSettingCheck(); @@ -196,7 +195,7 @@ } MachineState = MachineState.Running; OnMeasureStart?.BeginInvoke(null, null); OnMeasureStart?.Invoke(); var measurements = Config.MeasurementUnitCollection.Where(u => u.IsEnabled).ToList().DeepSerializeClone(); measurements.ForEach(m => @@ -226,9 +225,12 @@ Config.SnapshotPointCollection.Where(u => u.IsEnabled).ToList().ForEach(s => { _pauseHandle.WaitHandle.WaitOne(); _pausedHandle.Wait(); if (MachineState != MachineState.Running) if (MachineState == MachineState.Ready) return; if (MachineState != MachineState.Running && MachineState != MachineState.Pause) { throw new ProcessException("机台状态不在运行中,退出检测"); } @@ -336,10 +338,14 @@ { if (sender is ProductionMeasurement pMeasure) { lock (pMeasure) var production = productionList.FirstOrDefault(u => u.Barcode == pMeasure.Barcode); if (production == null) return; lock (production) { //检查是否全部完成 pMeasure.Measurements.ForEach(m => pMeasure.Measurements?.ForEach(m => { if (m.KeyUnitCollection.All(k => k.IsDone != null)) { @@ -381,7 +387,7 @@ indicator.ResultState = m.Spec.MeasureResult; pMeasure.ElementList.Add(indicator); //输出图形基元到界面 OnElementUpdated?.BeginInvoke(indicator, null, null); OnElementUpdated?.Invoke(indicator); SaveKeyImages(pMeasure.Barcode, m); @@ -494,7 +500,7 @@ MeasurementUnitResult measurementUnitResult = new MeasurementUnitResult(); measurementUnitResult.ProductionMeasurementRecordsId = productionMeasurementRecords.ID; measurementUnitResult.ProductionBarcode = productionMeasurementRecords.ProductionBarcode; measurementUnitResult.MeasurementName = measurementUnit.Name; measurementUnitResult.MeasurementName = measurementUnit.GetDisplayText(); measurementUnitResult.MeasurementType = measurementUnit.MeasureType; measurementUnitResult.MeasurementValue = measurementUnit.Spec.ActualValue.ToString(); measurementUnitResult.MeasurementResult = measurementUnit.Spec.MeasureResult.Value ? "OK" : "NG"; @@ -723,14 +729,14 @@ }); } string dir = Path.Combine(Config.ImageSaveFolder, "Clips", $"{snapshotName}_{DateTime.Now.ToString("HHmmss")}"); string dir = Path.Combine(Config.ImageSaveFolder, "Clips", $"{DateTime.Now.ToString("yyyyMMdd")}", $"{snapshotName}_{DateTime.Now.ToString("HHmmss")}"); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } Parallel.For(1, count.I + 1, (i) => //for (int i = 1; i <= count.I; i++) //Parallel.For(1, count.I + 1, (i) => for (int i = 1; i <= count.I; i++) { HOperatorSet.SelectObj(images, out HObject image, i); @@ -762,10 +768,11 @@ var results = _halconToolDict[keyToolKey].GetResultTuple("OUTPUT_Results").HTupleToDouble(); if (results.Count == 0 || results.Any(u => u < 0)) { LogAsync(DateTime.Now, $"{k.AliasName}检测结果异常", ""); LogAsync(DateTime.Now, $"{k.AliasName}原始数据异常", ""); } else { LogAsync(DateTime.Now, $"{k.AliasName}原始数据", $"{string.Join(" ", results)}"); resultDict = k.KeyResultList.ToDictionary(u => u, u => { int index = k.KeyResultList.IndexOf(u); @@ -784,7 +791,7 @@ //image.Dispose(); } ); //); //if (count.I != 1) //{ src/Bro.M071.Process/M071Process_MotionCard.cs
@@ -20,6 +20,7 @@ const int FULLRESETTIME = 5; object machineStateLock = new object(); //MachineState _machineStatePre = MachineState.Unknown; MachineState machineState = MachineState.Unknown; public MachineState MachineState { @@ -28,6 +29,8 @@ { if (machineState == value) return; //_machineStatePre = machineState; machineState = value; @@ -124,7 +127,36 @@ } OnMachineStateChanged?.Invoke(machineState); //if (_machineStatePre == MachineState.Running && machineState == MachineState.Pause) //{ // Pause(); //} //else if (_machineStatePre == MachineState.Pause && (machineState == MachineState.Running || machineState == MachineState.Ready)) //{ // Resume(); //} } } private void Pause() { #region 板卡暂停动作 outputCtrlCard.SetImmediatePause(); #endregion //_pauseHandle.WaitHandle.Reset(); //_pauseHandle.WaitResult = true; } private void Resume(bool isResumeContinueMoving) { #region 板卡恢复动作 outputCtrlCard.ResetImmediatePause(isResumeContinueMoving); #endregion //_pauseHandle.WaitHandle.Set(); //_pauseHandle.WaitResult = false; } private void MotionCardSettingCheck() @@ -203,24 +235,6 @@ [ProcessMethod("MotionCardBase", "Reset", "简单复位操作", InvokeType.TestInvoke)] public ProcessResponse Reset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { //if (opConfig == null) //{ // var monitorSet = Config.MonitorSetCollection.FirstOrDefault(u => u.MethodCode == "Reset"); // if (monitorSet == null) // throw new ProcessException("未配置默认复位操作"); // opConfig = monitorSet.OpConfig; // if (opConfig == null) // throw new ProcessException("未配置复位操作具体配置动作"); // if (invokeDevice == null) // { // invokeDevice = DeviceCollection.FirstOrDefault(u => u.Id == monitorSet.InvokeDevice); // if (invokeDevice == null) // throw new ProcessException("未配置复位操作执行设备"); // } //} if (ResetTimer == null) { ResetTimer = new Timer(FullReset, null, -1, -1); @@ -245,26 +259,23 @@ (invokeDevice as MotionCardBase).ResetAlarm(); RaisedAlarm(""); if (MachineState != MachineState.Pause) { MachineState = MachineState.Ready; } else { LogAsync(DateTime.Now, "设备暂停中,无法复位", ""); return new ProcessResponse(true); } if (IsEmergencyStopped) { RaisedAlarm("急停按钮未恢复,请执行大复位"); MachineState = MachineState.Alarm; return new ProcessResponse(true); } //if (opConfig.InputPara?.Count > 0) //{ // //大复位信号 // ResetTimer.Change(-1, opConfig.InputPara[0] == 1 ? FULLRESETTIME * 1000 : -1); //} //if (invokeDevice is MotionCardBase motionCard) //{ // motionCard.Run(opConfig); //} LogAsync(DateTime.Now, "普通复位动作完成", ""); @@ -287,28 +298,16 @@ [ProcessMethod("MotionCardBase", "FullReset", "大复位操作", InvokeType.TestInvoke)] public ProcessResponse FullReset(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { //if (opConfig == null) //{ // var monitorSet = Config.MonitorSetCollection.FirstOrDefault(u => u.MethodCode == "FullReset"); // if (monitorSet == null) // throw new ProcessException("未配置默认大复位操作"); if (!IsAllowedWork) { LogAsync(DateTime.Now, $"{SafetyMsg},大复位失败", ""); return new ProcessResponse(false); } // opConfig = monitorSet.OpConfig; // if (opConfig == null) // throw new ProcessException("未配置大复位操作具体配置动作"); // if (invokeDevice == null) // { // invokeDevice = DeviceCollection.FirstOrDefault(u => u.Id == monitorSet.InvokeDevice); // if (invokeDevice == null) // throw new ProcessException("未配置大复位操作执行设备"); // } //} //if (invokeDevice is MotionCardBase motionCard) //{ // motionCard.Run(opConfig); //} if (MachineState == MachineState.Pause) { Resume(false); } MachineState = MachineState.Resetting; MotionCardDefaultRun("FullReset", ref opConfig, ref invokeDevice); @@ -335,12 +334,12 @@ /// WaitHandle 暂停句柄 默认为非阻塞 可执行 /// WaitResult 暂停标志 true 正常执行 false 暂停中 /// </summary> ManualWaitConfirm _pauseHandle = new ManualWaitConfirm() { WaitHandle = new ManualResetEvent(true), WaitResult = true, }; MachineState _machineStateBeforePause = MachineState.Unknown; //ManualWaitConfirm _pauseHandle = new ManualWaitConfirm() //{ // WaitHandle = new ManualResetEvent(true), // WaitResult = true, //}; List<MachineState> _statesAllowPause = new List<MachineState>() { MachineState.Running, MachineState.Ready, MachineState.Pause }; [ProcessMethod("", "SwitchJobStatus", "流程状态切换", InvokeType.TestInvoke)] public ProcessResponse SwitchJobStatus(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) @@ -358,10 +357,7 @@ throw new ProcessException("未获取板卡设备"); bool? isToPause = null; //true 暂停 false 继续 //if (opConfig.InputPara != null && opConfig.InputPara.Count > 0) //{ // isToPause = opConfig.InputPara[0] == 1; //} if (opConfig.InputPara[0] == 10) { isToPause = false; @@ -373,59 +369,41 @@ if (isToPause == null) { if (!_pauseHandle.WaitResult) { #region 板卡暂停动作 motionDevice.SetImmediatePause(); #endregion _pauseHandle.WaitHandle.Reset(); _pauseHandle.WaitResult = true; _machineStateBeforePause = MachineState; MachineState = MachineState.Pause; } else if (!_pauseHandle.WaitResult) { #region 板卡恢复动作 motionDevice.ResetImmediatePause(); #endregion _pauseHandle.WaitHandle.Set(); _pauseHandle.WaitResult = false; MachineState = _machineStateBeforePause; } IsManualPaused = !IsManualPaused; } else { if (isToPause.Value) { if (!_pauseHandle.WaitResult) { #region 板卡暂停动作 motionDevice.SetImmediatePause(); #endregion //if (isToPause.Value) //{ // if (!_pauseHandle.WaitResult) // { // //#region 板卡暂停动作 // //motionDevice.SetImmediatePause(); // //#endregion _pauseHandle.WaitHandle.Reset(); _pauseHandle.WaitResult = true; MachineState = MachineState.Pause; } } else { if (!_pauseHandle.WaitResult) { #region 板卡恢复动作 motionDevice.ResetImmediatePause(); #endregion // //_pauseHandle.WaitHandle.Reset(); // //_pauseHandle.WaitResult = true; // MachineState = MachineState.Pause; // } //} //else //{ // if (!_pauseHandle.WaitResult) // { // //#region 板卡恢复动作 // //motionDevice.ResetImmediatePause(); // //#endregion _pauseHandle.WaitHandle.Set(); _pauseHandle.WaitResult = false; MachineState = _machineStateBeforePause; } } // //_pauseHandle.WaitHandle.Set(); // //_pauseHandle.WaitResult = false; // MachineState = _machineStatePre; // } //} IsManualPaused = isToPause.Value; } return new ProcessResponse(_pauseHandle.WaitResult); return new ProcessResponse(IsManualPaused); } ////[ProcessMethod("", "PauseJob", "暂停流程", InvokeType.TestInvoke)] @@ -633,6 +611,7 @@ { get => !(IsSafetyBeamTrigged || IsSafetyDoorTrigged || IsEmergencyStopped); } string SafetyMsg { get => $"{(IsSafetyBeamTrigged ? "安全光幕" : "")}{(IsSafetyDoorTrigged ? " 安全门" : "")}{(IsEmergencyStopped ? " 急停按钮" : "")}触发中"; @@ -641,21 +620,81 @@ #region 安全门 & 安全光线 bool isSafetyDoorTrigged = false; bool isSafetyBeamTrigged = false; bool isManualPaused = false; public bool IsSafetyDoorTrigged { get => !Config.IsSafetyDoorBlocked && isSafetyDoorTrigged; set => isSafetyDoorTrigged = value; get => (!Config.IsSafetyDoorBlocked) && isSafetyDoorTrigged; set { isSafetyDoorTrigged = value; CheckMachinePauseState(); } } public bool IsSafetyBeamTrigged { get => !Config.IsSafetyBeamBlocked && isSafetyBeamTrigged; set => isSafetyBeamTrigged = value; get => (!Config.IsSafetyBeamBlocked) && isSafetyBeamTrigged; set { isSafetyBeamTrigged = value; CheckMachinePauseState(); } } public bool IsManualPaused { get => isManualPaused; set { isManualPaused = value; CheckMachinePauseState(); } } ManualResetEventSlim _pausedHandle = new ManualResetEventSlim(true); MachineState _machineStateBeforePause = MachineState.Unknown; private async void CheckMachinePauseState() { await Task.Run(() => { if (IsMachinePaused) { _machineStateBeforePause = MachineState; MachineState = MachineState.Pause; _pausedHandle.Reset(); if (_machineStateBeforePause == MachineState.Running) { Pause(); } } else { if (MachineState == MachineState.Pause) { if (_machineStateBeforePause == MachineState.Running) { Resume(true); } _pausedHandle.Set(); RaisedAlarm(""); MachineState = _machineStateBeforePause; } } }); } public bool IsMachinePaused { get => IsSafetyBeamTrigged || IsSafetyDoorTrigged || IsManualPaused; } [ProcessMethod("", "SafetyDoorSignal", "安全门信号监控,正常ON,OFF时报警", InvokeType.TestInvoke)] public ProcessResponse SafetyDoorSignal(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { //if (MachineState != MachineState.Running && MachineState != MachineState.Pause) // return new ProcessResponse(true); if (opConfig.InputPara == null || opConfig.InputPara.Count == 0) throw new ProcessException("安全门监控未配置输入信号"); @@ -664,7 +703,6 @@ if (IsSafetyDoorTrigged) { RaisedAlarm("安全门未正常关闭"); MachineState = MachineState.Alarm; } return new ProcessResponse(true); @@ -673,8 +711,8 @@ [ProcessMethod("", "SafetyBeamSignal", "安全光幕信号监控,正常ON,OFF时报警", InvokeType.TestInvoke)] public ProcessResponse SafetyBeamSignal(IOperationConfig opConfig, IDevice invokeDevice, IDevice sourceDevice) { if (MachineState != MachineState.Running && MachineState != MachineState.Alarm) return new ProcessResponse(true); //if (MachineState != MachineState.Running && MachineState != MachineState.Pause) // return new ProcessResponse(true); if (opConfig.InputPara == null || opConfig.InputPara.Count == 0) throw new ProcessException("安全光幕监控未配置输入信号"); @@ -684,7 +722,6 @@ if (IsSafetyBeamTrigged) { RaisedAlarm("安全光线被遮挡"); MachineState = MachineState.Alarm; } return new ProcessResponse(true); src/Bro.UI.Config/MainFrm.cs
@@ -331,9 +331,14 @@ { foreach (var dock in dockPanelMain.Contents) { MenuFrmBase m = dock as MenuFrmBase; //MenuFrmBase m = dock as MenuFrmBase; m.DownloadProcess(_process); //m.DownloadProcess(_process); if (dock is MenuFrmBase menuFrm) { menuFrm.DownloadProcess(_process); } } } catch (Exception ex)