using Autofac; using Bro.Common.Base; using Bro.Common.Factory; using Bro.Common.Helper; using Bro.Common.Interface; using Bro.Common.Model; using Bro.M135.Common; using Bro.Process; using Newtonsoft.Json; using System.ComponentModel; using System.Drawing.Design; using System.Drawing.Imaging; using System.Drawing.Printing; using System.Reflection; using System.Windows.Forms.Design; using static Bro.Common.Helper.EnumHelper; namespace Bro.M141.Process { public class M141Config : ProcessConfigBase { [Category("打印机配置")] [Description("打印机配置集合")] [DisplayName("打印机配置集合")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List Printers { get; set; } = new List(); [Category("产品显示界面配置")] [Description("字体大小")] [DisplayName("字体大小")] public int FontSize_p { get; set; } = 15; [Category("产品显示界面配置")] [Description("每行列数")] [DisplayName("每行列数")] public int LineLimit_p { get; set; } = 30; [Category("工位信息")] [Description("工位信息配置集合")] [DisplayName("工位信息")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List WorkPositionCollection { get; set; } = new List(); [Category("检测配置")] [Description("检测配置集合,配置检测的工位,图片索引,相机和检测调用项关系")] [DisplayName("检测配置集合")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List MeasureBindCollection { get; set; } = new List(); [Category("检测超时设置")] [Description("检测超时设置,获取检测结果时的允许最大等待时间,单位ms")] [DisplayName("检测超时时间")] public int DetectTimeout { get; set; } = 1000; [Category("检测异常指示")] [Description("选择某个Spec,其表示检测过程中异常")] [DisplayName("异常指示标准")] [TypeConverter(typeof(SpecCodeSelectorConverter))] public string CheckErrorSpecCode { get; set; } = ""; [Category("位置度设置")] [Description("产品测量点位集合")] [DisplayName("产品测量点位集合")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List MeasurePointCollection { get; set; } = new List(); [Category("位置度设置")] [Description("检测项计算公式集合,设置包含组合点位的检测项")] [DisplayName("检测项计算公式集合")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List MeasureItemBinds { get; set; } = new List(); [Category("图片显示设置")] [Description("背景图片文件路径")] [DisplayName("背景图片")] [Editor(typeof(FileDialogEditor), typeof(UITypeEditor))] public string BackgroundImageFilePath { get; set; } [Category("NG和OK图片保存配置")] [Description("图片保存目录")] [DisplayName("图片保存目录")] [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))] public string NGImageFolder { get; set; } = ""; [ResCategory("NG和OK图片保存配置")] [ResDescription("NG图片保存格式")] [ResDisplayName("NG图片保存格式")] public ImageFormat ImageFormatNG { get; set; } = ImageFormat.Png; [ResCategory("NG和OK图片保存配置")] [ResDescription("OK图片保存格式")] [ResDisplayName("OK图片保存格式")] public ImageFormat ImageFormatOK { get; set; } = ImageFormat.Png; [Category("数据库配置")] [Description("IP")] [DisplayName("IP")] public string IPforall { get; set; } = "192.168.44.122"; [Category("数据库配置")] [Description("是否为终点设备")] [DisplayName("是否为终点设备")] public bool IsfinDevice { get; set; } = false; [Category("栏具条码配置")] [Description("当前栏具码")] [DisplayName("当前栏具码")] public string basketcode { get; set; } = "NoRead"; [Category("栏具条码配置")] [Description("本站是否读取栏具码")] [DisplayName("本站是否读取栏具码")] public bool Isreadbasketcode { get; set; } = false; [Category("PLC配置")] [Description("报警配置")] [DisplayName("报警配置")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List PLCAlarm { get; set; } = new List(); [Category("PLC配置")] [Description("心跳地址")] [DisplayName("心跳地址")] public int heartadd { get; set; } = 1505; } public class WorkPositionSet : IComplexDisplay { [Category("plc地址")] [Description("是否取图即完成")] [DisplayName("是否取图即完成")] public bool ispiccover { get; set; } = false; [Category("plc地址")] [Description("完成地址")] [DisplayName("完成地址")] public int plcover { get; set; } [Category("plc地址")] [Description("结果地址")] [DisplayName("结果地址")] public int plcresult { get; set; } [Category("plc地址")] [Description("物料码地址")] [DisplayName("物料码地址")] public int plcnum { get; set; } [Category("交互触发值")] [Description("交互触发信息,该交互信息表示当前该工位触发")] [DisplayName("交互触发信息")] public string TriggerValue { get; set; } [Category("工位名称")] [Description("工位名称")] [DisplayName("工位名称")] public string PositionName { get; set; } [Category("启用标志")] [Description("启用标志 true:该工位启用 false:该工位未启用")] [DisplayName("启用标志")] public bool IsEnabled { get; set; } = true; [Category("顺序设置")] [Description("是否是最后工位,最后工位完成时汇总产品数据结果")] [DisplayName("是否末工位")] public bool IsLastPosition { get; set; } = false; //[Category("反馈清理设置")] //[Description("true: 发送相机清理信号 false: 不发送相机清理信号")] //[DisplayName("发送清理信号开关")] //public bool IsSendClearSingal { get; set; } = false; //[Category("反馈清理设置")] //[Description("反馈相机清理时发送的文本信息")] //[DisplayName("反馈清理信息")] //public string ClearStr { get; set; } = "$,ClearOK"; public string GetDisplayText() { return $"{(IsEnabled ? "" : "禁用")} 工位 {PositionName} 交互触发值:{TriggerValue}"; } } public class PLCAlarms : IComplexDisplay { [Category("PLC配置")] [DisplayName("plc名称")] [Description("plc名称")] [TypeConverter(typeof(DeviceIdSelectorConverter))] public string plcname { get; set; } = ""; [Category("PLC配置")] [DisplayName("是否启用")] [Description("是否启用")] public bool isused { get; set; } = true; [Category("报警配置")] [Description("报警详情")] [DisplayName("报警详情")] [TypeConverter(typeof(CollectionCountConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List AlarmDetails { get; set; } = new List(); public string GetDisplayText() { return plcname + (isused ? "启用" : "禁用"); } } public class PLCAlarmDetails : IComplexDisplay, IImportFromFileInEditor { [Category("配置")] [DisplayName("首地址")] [Description("首地址")] public int address { get; set; } [Category("配置")] [DisplayName("子地址")] [Description("子地址")] public int address2 { get; set; } [Category("配置")] [DisplayName("报警名称")] [Description("报警名称")] public string alarmname { get; set; } = ""; [Browsable(false)] [JsonIgnore] public int value { get; set; } = -1; public string GetDisplayText() { return alarmname; } public IImportFromFileInEditor GetImportObject(string data, out string msg) { msg = ""; PLCAlarmDetails ret = new PLCAlarmDetails(); try { var temchar = data.Split(','); ret.alarmname = temchar[0]; ret.address =Convert.ToInt32(temchar[1]); ret.address2 = Convert.ToInt32(temchar[2]); } catch (Exception ex) { throw ex; } return ret; } public bool ICSVOutput(object o) { try { if (o is List Pl) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "CSV files (*.csv)|*.csv"; // 设置文件过滤器,只显示CSV文件 saveFileDialog.Title = "Save CSV File"; // 设置对话框标题 saveFileDialog.FileName = "PLCAlarms"; // 默认文件名 saveFileDialog.DefaultExt = "csv"; // 默认文件扩展名 string filePath = ""; if (saveFileDialog.ShowDialog() == DialogResult.OK) { filePath = saveFileDialog.FileName; // 获取用户选择的文件路径 } else { return false; } using (StreamWriter writer = new StreamWriter(filePath)) { // 写入标题行 writer.WriteLine("报警名称,首地址,子地址"); // 写入数据行 foreach (var row in Pl) { writer.WriteLine($"{row.alarmname},{row.address},{row.address2}"); } } } } catch { } return true; } } public class MeasureBind : IComplexDisplay, IHalconToolPath { [Category("索引配置")] [DisplayName("工位设置")] [Description("设置该检测项对应的工位,一般和触发方法对应的工位匹配")] [TypeConverter(typeof(WorkPositionNameConverter))] public string WorkPosition { get; set; } [Category("索引配置")] [DisplayName("检测索引")] [Description("设置该检测项对应的检测索引,一般指该工位的第几次检测")] public int CheckIndex { get; set; } [Category("索引配置")] [DisplayName("图像索引")] [Description("应对单次检测项需要多次拍照时,记录图片的索引号,从0开始")] public int ImageIndex { get; set; } = 0; [Category("启用配置")] [DisplayName("固定检测项")] [Description("true:该检测项是固定检测项目,必须执行 false:该检测是可变检测项目,流程中决定是否检测,默认不检测")] public bool IsFixed { get; set; } = true; [Category("取像设置")] [DisplayName("相机选择")] [Description("选择该检测项对应的相机")] [TypeConverter(typeof(DeviceIdSelectorConverter))] public string CameraId { get; set; } [Category("取像设置")] [Description("检测取像时的取像配置")] [DisplayName("取像配置")] [TypeConverter(typeof(ComplexObjectConvert))] [Editor(typeof(OperationConfigByCameraEditor), typeof(UITypeEditor))] public IOperationConfig SnapshotOpConfig { get; set; } = new CameraOperationConfigBase(); [Category("产品配置")] [DisplayName("产品索引")] [Description("一次取像可能对应单个产品或多个产品,配置对应的产品索引序号,从1开始")] [TypeConverter(typeof(SimpleCollectionConvert))] [Editor(typeof(SimpleCollectionEditor), typeof(UITypeEditor))] public List ProductIndices { get; set; } = new List(); [Category("产品配置")] [DisplayName("是否首工位")] [Description("如果是首工位,需要新建产品,否则从数据源中查找产品信息")] public bool IsFirstPosition { get; set; } = false; [Category("产品配置")] [DisplayName("支持队列缓存")] [Description("true: 寻找产品信息时可以从缓存队列中获取产品信息 false:不可以从缓存队列中获取产品信息,只能从数据库获取产品信息或者新建产品信息")] public bool IsEnabelQueryFromQueue { get; set; } = true; [Category("检测配置")] [Description("选择ML设备检测配置")] [DisplayName("检测配置")] [TypeConverter(typeof(DetectionConverter))] public string DetectionId { get; set; } [Category("检测配置")] [Description("从程序自定义检测方法中获取当前检测项")] [DisplayName("自定义检测方法")] [TypeConverter(typeof(MonitorSetSelectorConverter))] public string CustomizedMonitorId { get; set; } [Category("检测配置")] [Description("从程序自定义检测方法中获取当前检测项,该检测项用于多图组合运算时")] [DisplayName("自定义组合检测方法")] [TypeConverter(typeof(MonitorSetSelectorConverter))] public string CustomizedCombineMethodId { get; set; } [Category("图片保存配置")] [Description("NG图片保存开关,true:保存NG图片,false:不保存NG图片")] [DisplayName("NG图片保存开关")] public bool NGImageSwitch { get; set; } = false; [Category("图片保存配置")] [Description("OK图片保存开关,true:保存OK图片,false:不保存OK图片")] [DisplayName("OK图片保存开关")] public bool OKImageSwitch { get; set; } = false; [Category("图片保存设置")] [Description("该站检测图片保存时,保存的图片顺序后缀")] [DisplayName("图片保存顺序后缀")] public string ImageSaveSeq { get; set; } = "1"; public string GetDisplayText() { string cameraName = ""; string detectionName = "未指定"; string methodName = "未指定"; string combineMethodName = "未指定"; using (var scope = GlobalVar.Container.BeginLifetimeScope()) { var deviceList = scope.Resolve>(); cameraName = deviceList.FirstOrDefault(u => u.Id == CameraId)?.Name ?? "未指定"; var detection = deviceList.Select(u => u.InitialConfig).Where(u => u is MLInitialConfigBase).SelectMany(u => ((MLInitialConfigBase)u).DetectionConfigs).FirstOrDefault(u => u.Id == DetectionId); if (detection != null) { detectionName = detection.Name; } if (!string.IsNullOrWhiteSpace(CustomizedMonitorId)) { var config = scope.Resolve(); var curMethod = config.GetAllMonitorSet().FirstOrDefault(u => u.Id == CustomizedMonitorId); if (curMethod != null) { methodName = String.IsNullOrWhiteSpace(curMethod.Name) ? curMethod.MethodDesc : curMethod.Name; } curMethod = config.GetAllMonitorSet().FirstOrDefault(u => u.Id == CustomizedCombineMethodId); if (curMethod != null) { combineMethodName = String.IsNullOrWhiteSpace(curMethod.Name) ? curMethod.MethodDesc : curMethod.Name; } } } return $"工位{WorkPosition}第{CheckIndex}次检测产品{string.Join(",", ProductIndices.Select(u => u))},ML检测:{detectionName},自定义检测:{methodName},组合检测:{combineMethodName}"; } public List GetHalconToolPathList() { return (SnapshotOpConfig as IHalconToolPath).GetHalconToolPathList(); } } public class ContinuousNGAlarm : IComplexDisplay, IImportFromFileInEditor { [Category("缺陷类型")] [Description("选择需要监控的缺陷类型")] [DisplayName("缺陷类型")] public string DefectType { get; set; } [Category("连续NG报警")] [Description("连续NG数量阈值。该缺陷连续NG数量达到或超过该阈值时,发出报警")] [DisplayName("连续NG数量阈值")] public int ContinuousNumThreshold { get; set; } [Category("连续NG报警")] [Description("连续NG报警类型")] [DisplayName("连续NG报警类型")] public int ContinuousAlarmType { get; set; } = 1; [Category("时段报警")] [Description("监控时间段。监控该时间段内的缺陷数量,单位:min")] [DisplayName("监控时间段")] public int TimePeriod { get; set; } [Category("时段报警")] [Description("监控时间段内NG数量阈值。监控时间段内,该缺陷NG数量达到或超过该阈值时,发出报警")] [DisplayName("时间内NG数量阈值")] public int TimePeriodNumThresold { get; set; } [Category("时段报警")] [Description("时段报警类型")] [DisplayName("时段报警类型")] public int TimePeriodAlarmType { get; set; } = 2; [Category("启用设置")] [Description("true:启用该缺陷监控报警 false: 不启用该缺陷监控报警")] [DisplayName("启用监控")] public bool IsEnabled { get; set; } = true; public string GetDisplayText() { string display = $"{(IsEnabled ? "" : "已禁用")} 监控{DefectType} "; if (ContinuousNumThreshold > 0) { display += $"连续NG{ContinuousNumThreshold}个 "; } if (TimePeriodNumThresold > 0) { display += $"{TimePeriod}分钟内NG{TimePeriodNumThresold}个 "; } return display; } public IImportFromFileInEditor GetImportObject(string data, out string msg) { msg = ""; var dataList = data.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (dataList.Length < 6) { msg = "导入文件每行至少包含6段内容:缺陷类型,连续NG数量阈值,连续NG报警类型,监控时间段,时间内NG数量阈值,时段报警类型"; return null; } ContinuousNGAlarm ret = new ContinuousNGAlarm(); ret.DefectType = dataList[0]; ret.ContinuousNumThreshold = int.Parse(dataList[1]); ret.ContinuousAlarmType = int.Parse(dataList[2]); ret.TimePeriod = int.Parse(dataList[3]); ret.TimePeriodNumThresold = int.Parse(dataList[4]); ret.TimePeriodAlarmType = int.Parse(dataList[5]); return ret; } public bool ICSVOutput(object o) { //try //{ // if (o is ) // { // } //} //catch //{ //} return true; } } public class Printer : IComplexDisplay { [Category("打印机配置")] [DisplayName("名称")] [Description("名称")] [TypeConverter(typeof(DevicePrinter))] public string name { get; set; } = ""; [Category("打印机配置")] [DisplayName("位置")] [Description("位置")] public string station { get; set; } [Category("PLC配置")] [DisplayName("plc名称")] [Description("plc名称")] [TypeConverter(typeof(DeviceIdSelectorConverter))] public string plcname { get; set; } [Category("PLC配置")] [DisplayName("状态地址")] [Description("状态地址")] public int addstate { get; set; } [Category("PLC配置")] [DisplayName("结果地址")] [Description("结果地址")] public int addresult { get; set; } public string GetDisplayText() { return name; } } public class OperationConfigByCameraEditor : UITypeEditor { public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) { return UITypeEditorEditStyle.Modal; } public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) { IWindowsFormsEditorService edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService)); if (edSvc != null) { Form form = new Form { FormBorderStyle = FormBorderStyle.SizableToolWindow, StartPosition = FormStartPosition.CenterParent, Text = context.PropertyDescriptor.DisplayName + "--" + context.PropertyDescriptor.Description }; if (context.Instance is MeasureBind ssa) { IDevice camera = null; using (var scope = GlobalVar.Container.BeginLifetimeScope()) { var deviceList = scope.Resolve>(); camera = deviceList.FirstOrDefault(u => u.Id == ssa.CameraId); } if (camera != null) { var curCameraTypeAttr = camera.GetType().GetCustomAttribute(); var curOpconfigTypeAttr = value.GetType().GetCustomAttribute(); if (curCameraTypeAttr.TypeCode != (curOpconfigTypeAttr?.TypeCode ?? "")) { value = ConfigFactory.GetOperationConfig(curCameraTypeAttr.TypeCode); } } } PropertyGrid pg = new PropertyGrid { Dock = DockStyle.Fill, ToolbarVisible = false, SelectedObject = value }; form.Controls.Add(pg); form.ShowDialog(); value = pg.SelectedObject; return value; } return base.EditValue(context, provider, value); } } public class WorkPositionNameConverter : ComboBoxItemTypeConvert { public override Dictionary GetConvertDict(ITypeDescriptorContext context) { Dictionary dict = new Dictionary(); using (var scope = GlobalVar.Container.BeginLifetimeScope()) { var config = scope.Resolve(); if (config is M141Config iConfig) { dict = iConfig.WorkPositionCollection.Where(u => u.IsEnabled).ToDictionary(u => u.PositionName, u => u.PositionName); } } return dict; } } public interface IImageCheckOperationConfig : IOperationConfig { List Products { get; set; } IImageSet ImageSet { get; set; } string TriggerText { get; set; } string TriggerSource { get; set; } //CheckPoint CheckPoint { get; set; } string AlgorithemPath { get; set; } //string AlgorithemPath_CombineViews { get; set; } List SpecCollection { get; set; } //List SpecCollection_CombineViews { get; set; } List CheckPointList { get; set; } int Outindex { get; set; } IImageCheckOperationConfig Clone(); } public class PointSelector : IComplexDisplay, IImportFromFileInEditor { [ResCategory("点位选择")] [ResDisplayName("选择点位")] [ResDescription("从预设置的点位中选择")] [TypeConverter(typeof(MeasurePointNameSelectorConvertor))] public string pointCode { get; set; } public string GetDisplayText() { return pointCode == null ? "" : pointCode; } public IImportFromFileInEditor GetImportObject(string data, out string msg) { msg = ""; PointSelector ret = new PointSelector(); try { using (var scope = GlobalVar.Container.BeginLifetimeScope()) { var config = scope.Resolve(); if (config is M141Config iConfig) { if (iConfig.MeasurePointCollection.Any(u => u.Name == data)) { ret.pointCode = data; } else { throw new Exception(data + "不存在于点位集合中,不可录入"); } } } } catch (Exception ex) { throw ex; } return ret; } public bool ICSVOutput(object o) { try { if (o is List Pl) { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "CSV files (*.csv)|*.csv"; // 设置文件过滤器,只显示CSV文件 saveFileDialog.Title = "Save CSV File"; // 设置对话框标题 saveFileDialog.FileName = "PointSelectors"; // 默认文件名 saveFileDialog.DefaultExt = "csv"; // 默认文件扩展名 string filePath = ""; if (saveFileDialog.ShowDialog() == DialogResult.OK) { filePath = saveFileDialog.FileName; // 获取用户选择的文件路径 } else { return false; } using (StreamWriter writer = new StreamWriter(filePath)) { // 写入标题行 writer.WriteLine("点位"); // 写入数据行 foreach (var row in Pl) { writer.WriteLine(row.pointCode); } } } } catch { } return true; } } public class DevicePrinter : ComboBoxItemTypeConvert { public override Dictionary GetConvertDict(ITypeDescriptorContext context) { Dictionary table = new Dictionary(); table[""] = "未指定"; PrintDocument print = new PrintDocument(); string sDefault = print.PrinterSettings.PrinterName;//默认打印机名 foreach (string sPrint in PrinterSettings.InstalledPrinters)//获取所有打印机名称 { table[sPrint] = sPrint; } return table; } } [Device("ImageCheck", "图片检测操作配置", EnumHelper.DeviceAttributeType.OperationConfig)] public class ImageCheckOperationConfigBase : OperationConfigBase, IHalconToolPath, IImageCheckOperationConfig { [Browsable(false)] public List Products { get; set; } = new List(); [Browsable(false)] public IImageSet ImageSet { get; set; } = null; [Browsable(false)] public string TriggerText { get; set; } = ""; [Browsable(false)] public string TriggerSource { get; set; } = ""; [Category("算法脚本")] [Description("当前单张图片算法脚本文件路径")] [DisplayName("单图算法脚本")] [Editor(typeof(FileDialogEditor), typeof(UITypeEditor))] public string AlgorithemPath { get; set; } [Category("检测标准")] [Description("计算检测项集合")] [DisplayName("检测项集合")] [TypeConverter(typeof(ComplexObjectConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List SpecCollection { get; set; } = new List(); [Category("检测标准")] [Description("检测点位集合")] [DisplayName("检测点位集合")] [TypeConverter(typeof(ComplexObjectConvert))] [Editor(typeof(ComplexCollectionEditor), typeof(UITypeEditor))] public List CheckPointList { get; set; } = new List(); //[ResCategory("标定配置")] //[ResDescription("调用设备")] //[ResDisplayName("调用设备")] //[TypeConverter(typeof(DeviceIdSelectorConverter))] //public string ExecuteDevice { get; set; } = ""; [Category("数据输出配置")] [Description("配置数据输出时,代表数据输出序号,配置二次进算法时,代表数据量")] [DisplayName("数据输出序号")] public int Outindex { get; set; } = 0; public List GetHalconToolPathList() { return new List() { AlgorithemPath }; } public virtual IImageCheckOperationConfig Clone() { ImageCheckOperationConfigBase config = new ImageCheckOperationConfigBase(); config.AlgorithemPath = AlgorithemPath; config.SpecCollection = SpecCollection.Select(u => new SpecSelector() { SpecCode = u.SpecCode }).ToList(); config.Outindex = Outindex; config.TriggerStr = TriggerStr; //config.AlgorithemPath_CombineViews = AlgorithemPath_CombineViews; //config.SpecCollection_CombineViews = SpecCollection_CombineViews.Select(u => new SpecSelector() { SpecCode = u.SpecCode }).ToList(); config.CheckPointList = CheckPointList.Select(u => new PointSelector() { pointCode = u.pointCode }).ToList(); return config; } } [Device("OfflineDemo", "离线测试", DeviceAttributeType.OperationConfig)] public class OfflineDemoOperationConfig : OperationConfigBase { [Category("图片目录")] [Description("图片目录")] [DisplayName("图片目录")] [Editor(typeof(FoldDialogEditor), typeof(UITypeEditor))] public string ImageFolder { get; set; } [Category("启动配置")] [Description("true:启动离线测试 false:停止离线测试")] [DisplayName("测试开关")] public bool IsStart { get; set; } = true; [Category("检测功能")] [Description("图片在批量测试过程中最终图片结果会存储较慢需要设置延时确保图片不被资源自动释放")] [DisplayName("图片存图延时")] public int SaveImageTime { get; set; } = 0; [Category("检测功能")] [Description("true:启动OK测试 false:启动NG测试")] [DisplayName("是否测试OK图片")] public bool IsOK { get; set; } = true; } public class RealTimeAdjustDataDetail : IComplexDisplay { [Category("点位设置")] [Description("选择需要回传的数据点位")] [DisplayName("选择点位")] [TypeConverter(typeof(MeasurePointNameSelectorConvertor))] public string PointName { get; set; } [Category("点位设置")] [Description("选择数据点位的X坐标或者Y坐标")] [DisplayName("选择坐标")] public ContourEdge EdgeSelect { get; set; } = ContourEdge.X; [Category("检测项设置")] [Description("选择需要回传的SPC检测项数据")] [DisplayName("选择检测项")] [TypeConverter(typeof(SpecCodeSelectorConverter))] public string SpecCode { get; set; } [Category("检测项设置")] [Description("设置需要回传的SPC检测项数据的后缀,方便识别区分")] [DisplayName("检测项后缀")] public string SpecAfter { get; set; } = ""; [Category("数据范围")] [Description("数据最小值,小于该数值认为数据非法,不做回传,避免误导")] [DisplayName("数据最小值")] public double ValidRangeMin { get; set; } = -999; [Category("数据范围")] [Description("数据最大值,大于该数值认为数据非法,不做回传,避免误导")] [DisplayName("数据最大值")] public double ValidRangeMax { get; set; } = 999; public string GetDisplayText() { string desc = "未指定"; if (string.IsNullOrWhiteSpace(PointName)) { if (!string.IsNullOrWhiteSpace(SpecCode)) { desc = $"{SpecCode}{SpecAfter}"; } } else { desc = $"{PointName}-{EdgeSelect.ToString()}"; } return desc; } } }