using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using MaterialDesignThemes.Wpf;
using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Team.FFFeederService;
using Team.FFFeederService.Interfaces;
using TeamAAS_VP.Core;
using TeamAAS_VP.Data;
using TeamAAS_VP.Enums;
using TeamAAS_VP.Events;
using TeamAAS_VP.Interfaces;
using TeamAAS_VP.Models;
using TeamAAS_VP.Models.Calibration;
using TeamAAS_VP.Resources.Languages;
using TeamAAS_VP.Services;
using TeamAAS_VP.Views.Setting;
using static TeamAAS_VP.Core.StabilityAnalyzer;
namespace TeamAAS_VP.ViewModels.Product
{
public class VisionStaticAccuracyAnalyzerViewModel : BindableBase, IDialogAware
{
IRegionManager _regionManager;
IEventAggregator _eventAggregator;
IContainerProvider _container;
IDialogService _dialogService;
IFeederService _feederService;
IRobotService _robotService;
ICameraService _cameraService;
ISystemDatabaseService _systemDatabaseService;
ICalibrationService _calibrationService;
IConfigService _configService;
//测试过程中控制取消的CTS
CancellationTokenSource _cts;
#region 属性
private ICogImage _Image;
public ICogImage Image
{
get { return _Image; }
set { SetProperty(ref _Image, value); }
}
private Cognex.VisionPro.CogGraphicCollection _Graphic;
public Cognex.VisionPro.CogGraphicCollection Graphic
{
get { return _Graphic; }
set { SetProperty(ref _Graphic, value); }
}
private ProcedureModel _SelectProcedure;
///
/// 选中的流程
///
public ProcedureModel SelectProcedure
{
get { return _SelectProcedure; }
set
{
SetProperty(ref _SelectProcedure, value);
}
}
private ICamera _Camera;
public ICamera Camera
{
get { return _Camera; }
set { SetProperty(ref _Camera, value); }
}
private string _Message = "等待开始...";
public string Message
{
get { return _Message; }
set { SetProperty(ref _Message, value); }
}
private bool _IsRunning;
public bool IsRunning
{
get { return _IsRunning; }
set { SetProperty(ref _IsRunning, value); }
}
private CogToolBlock _VisionTool;
public CogToolBlock VisionTool
{
get { return _VisionTool; }
set { SetProperty(ref _VisionTool, value); }
}
private int _RepeatCount = 10;
///
/// 重复次数
///
public int RepeatCount
{
get { return _RepeatCount; }
set { SetProperty(ref _RepeatCount, value); }
}
private int _CurrentProgress;
///
/// 当前进度
///
public int CurrentProgress
{
get { return _CurrentProgress; }
set { SetProperty(ref _CurrentProgress, value); }
}
private int _SuccessCount;
///
/// 成功次数
///
public int SuccessCount
{
get { return _SuccessCount; }
set { SetProperty(ref _SuccessCount, value); }
}
private int _FailCount;
///
/// 失败次数
///
public int FailCount
{
get { return _FailCount; }
set { SetProperty(ref _FailCount, value); }
}
private double _SuccessRate;
///
/// 成功率
///
public double SuccessRate
{
get { return _SuccessRate; }
set { SetProperty(ref _SuccessRate, value); }
}
private DataTable _TestResult;
///
/// 测试结果列表DataTable
///
public DataTable TestResult
{
get { return _TestResult; }
set { SetProperty(ref _TestResult, value); }
}
private ObservableCollection _ResultDataColumns;
///
/// DataTable的列集合
///
public ObservableCollection ResultDataColumns
{
get { return _ResultDataColumns; }
set { SetProperty(ref _ResultDataColumns, value); }
}
//
private DataColumnInfo _SelectedDataColumn;
///
/// 选中的列
///
public DataColumnInfo SelectedDataColumn
{
get { return _SelectedDataColumn; }
set { SetProperty(ref _SelectedDataColumn, value); }
}
private SnackbarMessageQueue _MessageQueue;
public SnackbarMessageQueue MessageQueue
{
get { return _MessageQueue; }
set { SetProperty(ref _MessageQueue, value); }
}
//选中列分析结果
private StabilityMetrics _StabilityMetrics;
public StabilityMetrics StabilityMetrics
{
get { return _StabilityMetrics; }
set { SetProperty(ref _StabilityMetrics, value); }
}
private int _DelayTime = 200;
///
/// 延时时间
///
public int DelayTime
{
get { return _DelayTime; }
set { SetProperty(ref _DelayTime, value); }
}
#endregion
#region 命令
private DelegateCommand _ConfirmCommand;
public DelegateCommand ConfirmCommand =>
_ConfirmCommand ?? (_ConfirmCommand = new DelegateCommand(ExecuteConfirmCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _CancelCommand;
public DelegateCommand CancelCommand =>
_CancelCommand ?? (_CancelCommand = new DelegateCommand(ExecuteCancelCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _StartTestCommand;
public DelegateCommand StartTestCommand =>
_StartTestCommand ?? (_StartTestCommand = new DelegateCommand(ExecuteStartTestCommand, CanExecuteStartTestCommand).ObservesProperty(() => IsRunning));
private DelegateCommand _StopTestCommand;
public DelegateCommand StopTestCommand =>
_StopTestCommand ?? (_StopTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning));
//暂停测试命令
private DelegateCommand _PauseTestCommand;
public DelegateCommand PauseTestCommand =>
_PauseTestCommand ?? (_PauseTestCommand = new DelegateCommand(() => { _cts?.Cancel(); }, () => IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _ExportCSVCommand;
public DelegateCommand ExportCSVCommand =>
_ExportCSVCommand ?? (_ExportCSVCommand = new DelegateCommand(ExecuteExportCSVCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _ExportReportCommand;
public DelegateCommand ExportReportCommand =>
_ExportReportCommand ?? (_ExportReportCommand = new DelegateCommand(ExecuteExportReportCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _ClearDataCommand;
public DelegateCommand ClearDataCommand =>
_ClearDataCommand ?? (_ClearDataCommand = new DelegateCommand(ExecuteClearDataCommand, () => !IsRunning).ObservesProperty(() => IsRunning));
private DelegateCommand _SelectColumnCommand;
public DelegateCommand SelectColumnCommand =>
_SelectColumnCommand ?? (_SelectColumnCommand = new DelegateCommand(ExecuteSelectColumnCommand));
#endregion
#region 事件
#endregion
public VisionStaticAccuracyAnalyzerViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IDialogService dialogService,
IFeederService feederService, IRobotService robotService, ICameraService cameraService, ISystemDatabaseService systemDatabaseService, ICalibrationService calibrationService,
IConfigService configService)
{
_regionManager = regionManager;
_eventAggregator = ea;
_container = container;
_dialogService = dialogService;
_feederService = feederService;
_robotService = robotService;
_cameraService = cameraService;
_systemDatabaseService = systemDatabaseService;
MessageQueue = new SnackbarMessageQueue(TimeSpan.FromSeconds(1));
_calibrationService = calibrationService;
_configService = configService;
}
#region 方法
///
/// 确定
///
void ExecuteConfirmCommand()
{
_cts?.Cancel();
IDialogParameters parameters = new DialogParameters();
//parameters.Add("Tool", Tool);
//parameters.Add("RobotCameraRotationMatrix", RobotCameraRotationMatrix);
//parameters.Add("Angle", Angle);
RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parameters));
}
///
/// 取消
///
void ExecuteCancelCommand()
{
_cts?.Cancel();
IDialogParameters parameters = new DialogParameters();
//parameters.Add("Tool", Tool);
RequestClose?.Invoke(new DialogResult(ButtonResult.Cancel, parameters));
}
///
/// 开始测试
///
async void ExecuteStartTestCommand()
{
IsRunning = true;
_cts = new CancellationTokenSource();
CurrentProgress = 0;
SuccessCount = 0;
SuccessRate = 0;
FailCount = 0;
Message = "测试进行中...";
try
{
while (CurrentProgress < RepeatCount)
{
if (_cts.Token.IsCancellationRequested)
{
Message = "测试已取消!";
break;
}
(bool isSuccess, object[] Result) = await ExecutePhotoEx(CurrentProgress);
if (isSuccess)
{
SuccessCount++;
}
else
{
FailCount++;
}
TestResult.Rows.Add(Result);
ExecuteSelectColumnCommand();
await Task.Delay(DelayTime);
CurrentProgress++;
SuccessRate = (double)SuccessCount / CurrentProgress * 100;
SendTaskMessage($"测试进行中... {CurrentProgress}/{RepeatCount}");
}
if (CurrentProgress >= RepeatCount)
{
Message = "测试完成!";
}
}
catch (Exception ex)
{
LogHelper.WriteLogError("视觉静态重复测试时出错!", ex);
}
finally
{
IsRunning = false;
}
}
bool CanExecuteStartTestCommand()
{
return !IsRunning;
}
///
/// 清除数据
///
void ExecuteClearDataCommand()
{
if(TestResult!=null)
{
TestResult.Rows.Clear();
}
}
///
/// 导出测试报告
/// 使用 iTextSharp 生成 PDF,包含:标题、测试摘要、数据表格、每列稳定性分析结果
/// 详细伪代码:
/// 1. 校验 TestResult 是否存在数据,若无则提示并返回。
/// 2. 弹出保存对话框,获取保存路径,若取消返回。
/// 3. 创建 iTextSharp Document 与 PdfWriter,打开文档。
/// 4. 创建支持中文的 BaseFont(例如 STSongStd-Light + UniGB-UCS2-H)。
/// 5. 写入标题(居中、大号字体)。
/// 6. 写入测试摘要信息(测试时间、重复次数、成功/失败/成功率等),每项为单独段落或表格。
/// 7. 构建 PdfPTable:列数 = TestResult.Columns.Count,写入表头(加粗),逐行写入数据:
/// - 对于数值使用 InvariantCulture 格式化,空值写空字符串。
/// 8. 写入分析结果标题。
/// 9. 对于 ResultDataColumns 中的每列:
/// - 从 TestResult 读取该列所有数值(尝试转换为 double,忽略无法转换的项)。
/// - 如果样本数为 0,写入“样本数为0”提示并跳过。
/// - 调用 StabilityAnalyzer.AnalyzeStability(values) 获取指标对象。
/// - 遍历指标对象的公开属性,将属性名与值写入一个两列的 PdfPTable(或段落)。
/// 10. 关闭文档并释放资源。
/// 11. 捕获异常并记录日志,提示用户失败信息。
///
void ExecuteExportReportCommand()
{
try
{
if (TestResult == null || TestResult.Columns.Count == 0 || TestResult.Rows.Count == 0)
{
SendTaskMessage("无测试数据,无法导出报告。");
return;
}
var dlg = new Microsoft.Win32.SaveFileDialog
{
DefaultExt = "pdf",
Filter = "PDF 文件 (*.pdf)|*.pdf|所有文件 (*.*)|*.*",
FileName = "TestReport.pdf",
Title = "保存测试报告为 PDF"
};
bool? dlgResult = dlg.ShowDialog();
if (dlgResult != true)
return;
string path = dlg.FileName;
// 创建文档(A4, 边距)
var doc = new iTextSharp.text.Document(iTextSharp.text.PageSize.A4, 36, 36, 54, 54);
using (var fs = System.IO.File.Create(path))
{
var writer = iTextSharp.text.pdf.PdfWriter.GetInstance(doc, fs);
doc.Open();
// --- 字体加载:优先载入系统中文字体并以 IDENTITY_H 编码嵌入,保证中文显示 ---
iTextSharp.text.Font titleFont;
iTextSharp.text.Font headerFont;
iTextSharp.text.Font normalFont;
iTextSharp.text.pdf.BaseFont baseFont = null;
try
{
var fontsFolder = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
var candidates = new[]
{
"msyh.ttf",
"msyhbd.ttf",
"simsun.ttc,0", // 添加 ",0" 指定第一个字体
"simsun.ttc,1", // 第二个字体
"Microsoft YaHei.ttf",
"msyh.ttc,0", // 添加 ",0"
"msyh.ttc,1", // 添加 ",1"
"simhei.ttf"
};
foreach (var f in candidates)
{
var path1 = Path.Combine(fontsFolder, f);
try
{
baseFont = iTextSharp.text.pdf.BaseFont.CreateFont(
path1,
iTextSharp.text.pdf.BaseFont.IDENTITY_H,
iTextSharp.text.pdf.BaseFont.EMBEDDED
);
if (baseFont != null)
{
Console.WriteLine($"成功加载字体: {f}");
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"字体 {f} 加载失败: {ex.Message}");
continue;
}
}
}
catch
{
baseFont = null;
}
if (baseFont != null)
{
titleFont = new iTextSharp.text.Font(baseFont, 16, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK);
headerFont = new iTextSharp.text.Font(baseFont, 10, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK);
normalFont = new iTextSharp.text.Font(baseFont, 10, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLACK);
}
else
{
// 回退:如果未找到系统中文字体,使用内置 Helvetica(注意:可能无法正确显示中文)
titleFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 16, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK);
headerFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 10, iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.BLACK);
normalFont = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, 10, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.BLACK);
}
// 标题
var title = new iTextSharp.text.Paragraph("视觉静态精度测试报告", titleFont)
{
Alignment = iTextSharp.text.Element.ALIGN_CENTER,
SpacingAfter = 12f
};
doc.Add(title);
// 测试摘要
var metaTable = new iTextSharp.text.pdf.PdfPTable(2) { WidthPercentage = 100f };
metaTable.SetWidths(new float[] { 1f, 2f });
void AddMeta(string name, string value)
{
var cellName = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(name, headerFont)) { Border = 0, PaddingBottom = 6f };
var cellVal = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(value, normalFont)) { Border = 0, PaddingBottom = 6f };
metaTable.AddCell(cellName);
metaTable.AddCell(cellVal);
}
// include device info (line, station, fixture id) but exclude MES flags/urls
var device = _configService?.GetDeviceInfo() ?? _configService?.GetDeviceInfo();
if (device != null)
{
AddMeta("线别", device.Line ?? string.Empty);
AddMeta("站别", device.Station ?? string.Empty);
AddMeta("机台号", device.FixtureId ?? string.Empty);
}
AddMeta("导出时间", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
AddMeta("测试次数(目标)", RepeatCount.ToString());
AddMeta("当前进度", $"{CurrentProgress} / {RepeatCount}");
AddMeta("成功次数", SuccessCount.ToString());
AddMeta("失败次数", FailCount.ToString());
AddMeta("成功率(%)", SuccessRate.ToString("F2", System.Globalization.CultureInfo.InvariantCulture));
doc.Add(metaTable);
doc.Add(new iTextSharp.text.Paragraph(" ")); // 空行
// 数据表格
int colCount = TestResult.Columns.Count;
var table = new iTextSharp.text.pdf.PdfPTable(colCount) { WidthPercentage = 100f };
// 表头
foreach (System.Data.DataColumn col in TestResult.Columns)
{
var cell = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(col.ColumnName, headerFont))
{
HorizontalAlignment = iTextSharp.text.Element.ALIGN_CENTER,
BackgroundColor = new iTextSharp.text.BaseColor(230, 230, 230),
Padding = 4f
};
table.AddCell(cell);
}
// 数据行
foreach (System.Data.DataRow row in TestResult.Rows)
{
for (int c = 0; c < colCount; c++)
{
object val = row[c];
string s;
if (val == null || val == DBNull.Value)
s = "";
else if (val is double || val is float || val is decimal)
s = Convert.ToDouble(val).ToString("G", System.Globalization.CultureInfo.InvariantCulture);
else
s = val.ToString();
var cell = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(s, normalFont)) { Padding = 4f };
table.AddCell(cell);
}
}
doc.Add(table);
doc.NewPage();
// 分析结果
var analysisTitle = new iTextSharp.text.Paragraph("分析结果", titleFont) { SpacingAfter = 8f };
doc.Add(analysisTitle);
if (ResultDataColumns != null && ResultDataColumns.Count > 0)
{
foreach (var colInfo in ResultDataColumns)
{
try
{
// 收集数值
var values = new System.Collections.Generic.List();
foreach (System.Data.DataRow row in TestResult.Rows)
{
object v = row[colInfo.ColumnIndex];
if (v == null || v == DBNull.Value) continue;
double d;
if (v is double) d = (double)v;
else if (v is float) d = Convert.ToDouble((float)v);
else if (v is decimal) d = Convert.ToDouble((decimal)v);
else if (v is int) d = Convert.ToDouble((int)v);
else if (v is long) d = Convert.ToDouble((long)v);
else
{
if (!double.TryParse(v.ToString(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out d))
continue;
}
values.Add(d);
}
var colHeader = new iTextSharp.text.Paragraph(colInfo.ColumnName, headerFont) { SpacingBefore = 6f, SpacingAfter = 4f };
doc.Add(colHeader);
if (values.Count == 0)
{
doc.Add(new iTextSharp.text.Paragraph("样本数为 0,无法计算。", normalFont));
continue;
}
// 计算稳定性指标
StabilityMetrics metrics = StabilityAnalyzer.AnalyzeStability(values.ToArray());
// 将指标写成两列表(属性名 / 值)
var metricsTable = new iTextSharp.text.pdf.PdfPTable(2) { WidthPercentage = 60f, SpacingAfter = 6f };
metricsTable.SetWidths(new float[] { 1f, 1f });
var props = metrics.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var p in props)
{
object pv = p.GetValue(metrics);
string pvStr;
if (pv == null) pvStr = "";
else if (pv is double) pvStr = ((double)pv).ToString("G", System.Globalization.CultureInfo.InvariantCulture);
else pvStr = pv.ToString();
var pc = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(p.Name, normalFont)) { Padding = 4f };
var vc = new iTextSharp.text.pdf.PdfPCell(new iTextSharp.text.Phrase(pvStr, normalFont)) { Padding = 4f };
metricsTable.AddCell(pc);
metricsTable.AddCell(vc);
}
doc.Add(metricsTable);
}
catch (Exception exCol)
{
LogHelper.WriteLogError($"导出报告时处理列[{colInfo.ColumnName}]出错", exCol);
doc.Add(new iTextSharp.text.Paragraph($"处理列 {colInfo.ColumnName} 时出错: {exCol.Message}", normalFont));
}
}
}
else
{
doc.Add(new iTextSharp.text.Paragraph("无用于分析的数值列。", normalFont));
}
doc.Close();
writer.Close();
}
SendTaskMessage($"已导出测试报告到:{path}");
}
catch (Exception ex)
{
LogHelper.WriteLogError("导出测试报告时出错", ex);
SendTaskMessage($"导出测试报告失败:{ex.Message}");
}
}
///
/// 导出测试数据为CSV文件
///
void ExecuteExportCSVCommand()
{
try
{
if (TestResult == null || TestResult.Columns.Count == 0 || TestResult.Rows.Count == 0)
{
SendTaskMessage("无测试数据,无法导出。");
return;
}
var dlg = new Microsoft.Win32.SaveFileDialog
{
DefaultExt = "csv",
Filter = "CSV 文件 (*.csv)|*.csv|所有文件 (*.*)|*.*",
FileName = "TestResult.csv",
Title = "保存测试结果为 CSV"
};
bool? dlgResult = dlg.ShowDialog();
if (dlgResult != true)
return;
string path = dlg.FileName;
var sb = new System.Text.StringBuilder();
// 辅助:CSV 字段转义
Func EscapeCsv = (s) =>
{
if (s == null) return "";
bool mustQuote = s.Contains(",") || s.Contains("\"") || s.Contains("\r") || s.Contains("\n");
string esc = s.Replace("\"", "\"\"");
return mustQuote ? $"\"{esc}\"" : esc;
};
// include device info at top of CSV
var device = _configService?.GetDeviceInfo();
if (device != null)
{
sb.AppendLine("设备信息");
sb.AppendLine($"线别,{EscapeCsv(device.Line)}");
sb.AppendLine($"站别,{EscapeCsv(device.Station)}");
sb.AppendLine($"机台号,{EscapeCsv(device.FixtureId)}");
sb.AppendLine();
}
// 1. 写入表头
for (int c = 0; c < TestResult.Columns.Count; c++)
{
if (c > 0) sb.Append(",");
sb.Append(EscapeCsv(TestResult.Columns[c].ColumnName));
}
sb.AppendLine();
// 2. 写入数据行
foreach (System.Data.DataRow row in TestResult.Rows)
{
for (int c = 0; c < TestResult.Columns.Count; c++)
{
if (c > 0) sb.Append(",");
object val = row[c];
if (val == DBNull.Value || val == null)
{
sb.Append("");
}
else
{
// 保持数值格式,其他转为字符串
string outStr;
if (val is double || val is float || val is decimal)
outStr = Convert.ToString(val, System.Globalization.CultureInfo.InvariantCulture);
else if (val is int || val is long || val is short || val is byte)
outStr = val.ToString();
else if (val is bool)
outStr = (bool)val ? "True" : "False";
else
outStr = val.ToString();
sb.Append(EscapeCsv(outStr));
}
}
sb.AppendLine();
}
// 3. 在末尾追加分析结果
sb.AppendLine(); // 空行
sb.AppendLine("分析结果");
sb.AppendLine("列名,指标,值"); // CSV 表头:列名,指标,值
if (ResultDataColumns != null)
{
foreach (var colInfo in ResultDataColumns)
{
try
{
List values = new List();
foreach (System.Data.DataRow row in TestResult.Rows)
{
object v = row[colInfo.ColumnIndex];
if (v != DBNull.Value && v != null)
{
double d;
// 支持不同数字类型
if (v is double) d = (double)v;
else if (v is float) d = Convert.ToDouble((float)v);
else if (v is decimal) d = Convert.ToDouble((decimal)v);
else if (v is int) d = Convert.ToDouble((int)v);
else if (v is long) d = Convert.ToDouble((long)v);
else
{
if (!double.TryParse(v.ToString(), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out d))
continue;
}
values.Add(d);
}
}
if (values.Count == 0)
{
sb.AppendLine($"{EscapeCsv(colInfo.ColumnName)},{EscapeCsv("样本数")},{0}");
continue;
}
// 调用稳定性分析
StabilityMetrics metrics = StabilityAnalyzer.AnalyzeStability(values.ToArray());
// 使用反射枚举 metrics 的公开属性并写入 CSV
var props = metrics.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var p in props)
{
object pv = p.GetValue(metrics);
string pvStr = pv == null ? "" : (pv is double ? Convert.ToString((double)pv, System.Globalization.CultureInfo.InvariantCulture) : pv.ToString());
sb.AppendLine($"{EscapeCsv(colInfo.ColumnName)},{EscapeCsv(p.Name)},{EscapeCsv(pvStr)}");
}
}
catch (Exception exCol)
{
LogHelper.WriteLogError($"导出分析结果时处理列[{colInfo.ColumnName}]出错", exCol);
sb.AppendLine($"{EscapeCsv(colInfo.ColumnName)},{EscapeCsv("Error")},{EscapeCsv(exCol.Message)}");
}
}
}
// 写入文件(UTF8,无 BOM,若需 BOM 可使用 new UTF8Encoding(true))
System.IO.File.WriteAllText(path, sb.ToString(), System.Text.Encoding.UTF8);
SendTaskMessage($"已导出测试结果到:{path}");
}
catch (Exception ex)
{
LogHelper.WriteLogError("导出CSV时出错", ex);
SendTaskMessage($"导出CSV失败:{ex.Message}");
}
}
///
/// 选中列时触发
///
void ExecuteSelectColumnCommand()
{
try
{
//如果选中列为空,则直接返回
if (SelectedDataColumn == null)
return;
//获取表的指定列的所有数据集合
List dataList = new List();
foreach (DataRow row in TestResult.Rows)
{
if (row[SelectedDataColumn.ColumnIndex] != DBNull.Value)
{
dataList.Add(Convert.ToDouble(row[SelectedDataColumn.ColumnIndex]));
}
}
//如果数据量小于10,则不进行分析
if (dataList.Count < 10)
{
//MessageQueue.Enqueue("选中列的数据量小于10,无法进行统计分析!");
return;
}
//进行稳定性分析
StabilityMetrics metrics = StabilityAnalyzer.AnalyzeStability(dataList.ToArray());
App.Current.Dispatcher.Invoke(() =>
{
StabilityMetrics = metrics;
});
}
catch (Exception ex)
{
LogHelper.WriteLogError("选中列的数据分析数据稳定性时出错!", ex);
}
}
///
/// 执行相机拍照并运行 ToolBlock,返回是否成功并通过 out 参数返回 Outputs、图像和图形集合。
///
///
///
public Task<(bool isSuccess, object[] Result)> ExecutePhotoEx(int index)
{
return Task.Run(() =>
{
CogToolBlockTerminalCollection outputCollection;
List