using HMI.Core.Entity; using HMI.Core.Manager; using HMI.Core.Setting; using HMI.Core.Util; using HMI.Util; using NationalInstruments.TestStand.Interop.API; using NPOI.HSSF.UserModel; using NPOI.SS.Formula.Functions; using NPOI.SS.UserModel; using Plugin.TsExecution.Entity; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.IO; using System.Runtime.CompilerServices; using System.Timers; using System.Windows; using System.Windows.Controls; namespace Plugin.TsExecution { /// /// SingleControl.xaml 的交互逻辑 /// public partial class SingleControl : UserControl, INotifyPropertyChanged { #region ... public event PropertyChangedEventHandler PropertyChanged; protected void Set([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } protected void Set(ref T old, T @new, [CallerMemberName] string propertyName = null) { old = @new; if (propertyName != null) { Set(propertyName); } } #endregion private int index; private string CountIniPath; private string status = "Ready"; private ScreenTouch[] screens; private ScreenGrid screenGrid; public string Status { get { return status; } set { Set(ref status, value); } } private double totalNum; public double TotalNum { get => totalNum; private set { Set(ref totalNum, value); } } private int passNum; public int PassNum { get => passNum; private set { Set(ref passNum, value); } } private int failNum; public int FailNum { get => failNum; private set { Set(ref failNum, value); } } private double passRate; public double PassRate { get => passRate; private set { Set(ref passRate, value); } } public string NumInfo { get => this.lang("Ts.NumInfo", TotalNum, PassNum, FailNum, string.Format("{0:0.00}", PassRate)); } public string TestInfo { get => this.lang("Ts.TestInfo", Barcode, ElapseTime); } private string barcode = string.Empty; public string Barcode { get { return barcode; } set { Set(ref barcode, value); } } private string model = string.Empty; public string Model { get { return model; } set { Set(ref model, value); } } private string elapseTime = "00:00:00"; public string ElapseTime { get { return elapseTime; } set { if (value == "Start Timing") { this.refreshTimer.Enabled = true; TestStartTime = DateTime.Now; StepStartTime = DateTime.Now; } else { this.refreshTimer.Enabled = false; if (value != "Stop Timing") { Set(ref elapseTime, value + "s"); Set("TestInfo"); } } } } private string socketName = string.Empty; public string SocketName { get { return socketName; } set { Set(ref socketName, value); } } private ObservableCollection _datasource = new ObservableCollection(); public ObservableCollection Datasource { get => _datasource; set { Set(ref _datasource, value); } } private DateTime TestStartTime = new DateTime(); private DateTime StepStartTime = new DateTime(); private TimeSpan TimeCount = new TimeSpan(); private System.Timers.Timer refreshTimer; private string currentStep = ""; public string CurrentStep { get => currentStep; set { Set(ref currentStep, value); } } private int _probeCount; public int ProbeCount { get => _probeCount; set { Set(ref _probeCount, value); try { if (ProbeWarn <= 0) probeCountAlarm.Visibility = Visibility.Collapsed; else if (value >= ProbeWarn) probeCountAlarm.Visibility = Visibility.Visible; else probeCountAlarm.Visibility = Visibility.Collapsed; } catch { } } } /// /// 进度值 /// private int _processValue; public int ProcessValue { get => _processValue; set { Set(ref _processValue, value); } } public string ProcessValueLabel { get { if (ProcessValue > 0) return $"{ProcessValue}%"; return ""; } set { } } public void SetSimpleUI(bool flag) { if (flag) { simplePanel.Visibility = Visibility.Visible; detailPanel.Visibility = Visibility.Collapsed; } else { simplePanel.Visibility = Visibility.Collapsed; detailPanel.Visibility = Visibility.Visible; } } private int _probeWarn; public int ProbeWarn { get => _probeWarn; private set { Set(ref _probeWarn, value); } } private bool isAutoMode; public bool IsAutoMode { get => isAutoMode; set { Set(ref isAutoMode, value); } } public SingleControl(int Index, string CountIniPath, int probeWarn) { DataContext = this; this.CountIniPath = CountIniPath; this.index = Index; ProbeWarn = probeWarn; refreshTimer = new System.Timers.Timer() { Interval = 100 }; refreshTimer.Elapsed += RefreshTimer_Elapsed; ReadCounter(); InitializeComponent(); RefreshProbeCount(null); try { var value = ParameterManager.GetCommonParameterByName("AutoTestMode"); IsAutoMode = bool.Parse(value.Value); } catch { IsAutoMode = true; } //if (ProbeWarn > 0) //{ // probeWarnPanel.Visibility = Visibility.Visible; //} //else //{ // probeWarnPanel.Visibility = Visibility.Collapsed; //} } private void RefreshTimer_Elapsed(object sender, ElapsedEventArgs e) { //Dispatcher.Invoke(() => //{ // var data = PluginLoader.Instance.Plugins.FirstOrDefault(p => p.Name == "TS"); // if (data?.Content is TsExecution ts) // { // if (Status == "Testing") // { // ts.UpdatePositionStatus(index, "Passed"); // } // else // { // ts.UpdatePositionStatus(index, "Testing"); // } // } //}); //AddTestData("1", "1", "1", "1", "1", "1", "1"); TimeCount = DateTime.Now - TestStartTime; elapseTime = string.Format("{0:00}:{1:00}:{2:00}", TimeCount.Hours, TimeCount.Minutes, TimeCount.Seconds); Set("ElapseTime"); Set("TestInfo"); } public SequenceContext SequenceFileContext { get; set; } /// /// 获取TS的每步测试的数据添加到表格 /// 项目名称,测试参数,测试值,上限,下限,单位,结果 /// /// public void AddTestData(string name, string step_name, string value, string HightLimit, string LowLimit, string unit, string Status) { try { var data = new TestStep { Name = name, Step = step_name, Value = value, LimitUp = HightLimit, LimitDown = LowLimit, Unit = unit, Result = Status }; table.Dispatcher.Invoke(new Action(() => { var now = DateTime.Now; var span = now - StepStartTime; StepStartTime = now; data.ConsumeTime = $"{(span.TotalMilliseconds / 1000d).ToString("F2")}s"; Datasource.Add(data); table.ScrollIntoView(data); })); } catch (Exception ex) { //屏蔽错误 } } public void UpdateStatus(string status) { if (status == "Passed") { UpdateTestCounter(true); } else if (status == "Error" || status == "Failed") { UpdateTestCounter(false); } else if (Status != "Testing" && status == "Testing") { UpdateProbeCount(ProbeCount + 1); } Status = status; } public void IniTestData() { Datasource.Clear(); } /// /// 设置测试进度条 /// /// public void SetTestProcess(int ProcessVal) { ProcessValue = ProcessVal; Set("ProcessValueLabel"); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { this.UpdateTestCounter(null); } private void UpdateTestCounter(bool? result) { if (result == true) { PassNum += 1; //Interlocked.Increment(ref passNum); //Set("PassNum"); } else if (result == false) { FailNum += 1; //Interlocked.Increment(ref failNum); //Set("FailNum"); } TotalNum = PassNum + FailNum; if (TotalNum != 0) { PassRate = ((double)PassNum / TotalNum); } else { PassRate = 0.0; } Set("NumInfo"); this.WriteCounter(); } private void WriteCounter() { IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "Pass", this.passNum.ToString(), this.CountIniPath); IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "Fail", this.failNum.ToString(), this.CountIniPath); } private void ReadCounter() { try { this.PassNum = Convert.ToInt32(IniFileHelper.ReadIniData("Socket" + this.index.ToString(), "Pass", "", CountIniPath)); this.FailNum = Convert.ToInt32(IniFileHelper.ReadIniData("Socket" + this.index.ToString(), "Fail", "", CountIniPath)); } catch (Exception ex) { //do nothing } } public void ResetCounter() { this.PassNum = 0; this.FailNum = 0; this.UpdateTestCounter(null); } public void WriteToExcel(string path) { Dispatcher.Invoke(() => { try { string suffix = Path.GetExtension(path); if (!string.Equals(".xlsx", suffix, StringComparison.OrdinalIgnoreCase) && !string.Equals(".xls", suffix, StringComparison.OrdinalIgnoreCase)) { path = path.Replace(suffix, ".xls"); } FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) { fi.Directory.Create(); //文件不存在,创建文件 } List rows = new List(); rows.Add(new string[] { "测试时间", "测试人", "测试设备", "条形码", "测试结果" }); rows.Add(new string[] { DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), UserInfo.User.Name, ParamSetting.StationName, Barcode, Status }); rows.Add(new string[] { "项目名称", "测试参数", "测试值", "上限", "下限", "单位", "结果" }); if (Datasource != null && Datasource.Count > 0) { foreach (var data in Datasource) { rows.Add(new string[] { data.Name, data.Step, data.Value, data.LimitUp, data.LimitDown, data.Unit, data.Result }); } } ExcelHelper.ExportExcel(path, rows); } catch (Exception ex) { TsExecution.logger.Error("Write CSV File Failed.", ex); } }); } public void WriteToCSV(string path) { Dispatcher.Invoke(() => { try { FileInfo fi = new FileInfo(path); if (!fi.Directory.Exists) { fi.Directory.Create(); //文件不存在,创建文件 } using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8)) { string title = "项目名称,测试参数,测试值,上限,下限,单位,结果"; sw.WriteLine(title); if (Datasource != null && Datasource.Count > 0) { foreach (var data in Datasource) { sw.WriteLine($"{data.Name},{data.Step},{data.Value},{data.LimitUp},{data.LimitDown},{data.Unit},{data.Result}"); } } } } catch (Exception ex) { TsExecution.logger.Error("Write CSV File Failed.", ex); } }); } public void ShowPausePanel() { pausePanel.Visibility = Visibility.Visible; } private void Button_Click(object sender, RoutedEventArgs e) { Button btn = sender as Button; switch (btn.Name) { case "clear": UpdateProbeCount(0); break; case "cancelPauseBtn": SequenceFileContext?.StationGlobals.SetValBoolean($"StationState.IsContinue_{index}", 1, false); pausePanel.Visibility = Visibility.Collapsed; break; case "continuePauseBtn": SequenceFileContext?.StationGlobals.SetValBoolean($"StationState.IsContinue_{index}", 1, true); pausePanel.Visibility = Visibility.Collapsed; break; case "scannerSetting": //ScannerSetting setting = new ScannerSetting() //{ // Owner = Window.GetWindow(this) //}; //setting.Open(true, $"Socket{index}", CountIniPath); ShowScannerPanel(); break; case "scannerOkBtn": SendSnr2Ts(); break; default: break; } } public void ShowScannerPanel() { //scannerPanel.Visibility = Visibility.Visible; } private void SendSnr2Ts() { } private void pausePanel_Loaded(object sender, RoutedEventArgs e) { if (sender == pausePanel) { var can = pausePanel; var modal = visualModal; Canvas.SetLeft(modal, (pausePanel.ActualWidth - visualModal.ActualWidth) / 2); Canvas.SetTop(modal, (pausePanel.ActualHeight - visualModal.ActualHeight) / 2); } else { //var can = scannerPanel; //var modal = scannerVisualModal; //Canvas.SetLeft(modal, (scannerPanel.ActualWidth - scannerVisualModal.ActualWidth) / 2); //Canvas.SetTop(modal, (scannerPanel.ActualHeight - scannerVisualModal.ActualHeight) / 2); } } public void RefreshScreen(int[][] configs) { //foreach (UIElement item in canvas.Children) //{ // if (item is ScreenTouch) // { // canvas.Children.Remove(item); // } //} screenContainer.Child = null; screenGrid = new ScreenGrid(1, configs.Length); screens = new ScreenTouch[configs.Length]; int space = 2 * (screens.Length + 1); for (int i = 0; i < configs.Length; i++) { var screen = new ScreenTouch(configs[i][0], configs[i][1]) { Width = Math.Max((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length, 0), Height = Math.Max((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length / 16 * 9, 0) }; screens[i] = screen; screenGrid.AddScreen(screen, 0, i); } screenContainer.Child = screenGrid; //canvas.Children.Add(screens[0]); //Canvas.SetBottom(screens[0], 0); //Canvas.SetRight(screens[0], 0); //Panel.SetZIndex(screens[0], 999); } public void DrawScreenPoint(int index, int x, int y) { screens[index].DrawPoint(x, y); } /// /// 绘图之前清空已有的 /// /// /// public void DrawScreenPoints(int index, int[][] points) { screens[index].DrawPoints(points); } /// /// 绘图之前不清空已有的 /// /// /// public void DrawNewScreenPoints(int index, int[][] points) { screens[index].DrawNewPoints(points); } public void ClearScreenPoint(int index) { screens[index].Clear(); } public void RefreshProbeCount(ProductData product) { try { var num = IniFileHelper.ReadIniData($"Socket{this.index.ToString()}", "ProbeCount", "0", this.CountIniPath); this.ProbeCount = int.Parse(num); } catch (Exception ex) { this.ProbeCount = 0; } } /// /// 更新探针使用次数 /// /// private void UpdateProbeCount(int count) { /// 写到配置文件 IniFileHelper.WriteIniData("Socket" + this.index.ToString(), "ProbeCount", count.ToString(), this.CountIniPath); ProbeCount = count; } public void RefreshProduct(ProductData product) { if (product == null) { screenContainer.Child = null; return; } try { string screenSize = ProductManager.GetParameterByProductAndName(product.Name, "ScreenTouch")?.Value; if (string.IsNullOrEmpty(screenSize)) { screenContainer.Child = null; return; } string[] arr = screenSize.Split(';'); int[][] configs = new int[arr.Length][]; for (int i = 0; i < arr.Length; i++) { string[] size = arr[i].Split(','); configs[i] = new int[2] { int.Parse(size[0]), int.Parse(size[1]) }; } RefreshScreen(configs); } catch (Exception ex) { TsExecution.logger.Error("RefreshProduct Failed.", ex); screenContainer.Child = null; } } private void control_SizeChanged(object sender, SizeChangedEventArgs e) { if (screenGrid == null) { return; } //screenGrid.Height = tableHeader.ActualHeight - 2; //screenGrid.Width = tableHeader.ActualHeight / 9 * 16 - 2; int space = 2 * (screens.Length + 1); for (int i = 0; i < screens.Length; i++) { var screen = screens[i]; screen.Width = Math.Max(Math.Floor((tableHeader.ActualHeight / 9 * 16 - space) / screens.Length), 0); screen.Height = Math.Max(Math.Floor(screen.Width / 16 * 9), 0); } } private void screenContainer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { if (e.ClickCount == 2) { new ScreenTouchWin(screens) { Owner = Window.GetWindow(this) }.ShowDialog(); } } } }