alielie
2026-04-23 ef52fd6fd07508883dce4eb002acda59f0169e59
Plugin.TsExecution/TsExecution.xaml.cs
@@ -1,15 +1,17 @@
using HMI.Base;
using HMI.Core;
using HMI.Core.Api;
using HMI.Core.Entity;
using HMI.Core.Manager;
using HMI.Core.Setting;
using HMI.Core.Util;
using HMI.UI;
using HMI.MQUtil;
using HMI.UI.Util;
using HMI.Util;
using log4net;
using NationalInstruments.TestStand.Interop.API;
using NationalInstruments.TestStand.Interop.UI.Ax;
using Panuon.WPF.UI;
using Plugin.TsSupport;
using ScottPlot;
using ScottPlot.Plottables;
using System;
@@ -18,19 +20,18 @@
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.DataVisualization.Charting;
using System.Xml.Linq;
namespace Plugin.TsExecution
{
    /// <summary>
    /// UserControl1.xaml 的交互逻辑
    /// </summary>
    public partial class TsExecution : PluginControl
    public partial class TsExecution : PluginMaskControl
    {
        #region TestStand事件
        /// <summary>
@@ -50,6 +51,8 @@
        private SequenceFile modeSeq = null;
        public AxApplicationMgr AxApplicationMgr;
        private Execution execution = null;
        private SequenceContext sequenceContext = null;
        private Chart chart;
        #endregion
@@ -92,13 +95,33 @@
        private ProductData selectedProduct;
        private MSMQHelper mSMQHelper = new MSMQHelper("HMI_Alarm");
        public ProductData SelectedProduct
        {
            get { return selectedProduct; }
            set
            {
                Set(ref selectedProduct, value);
                CurrentProductModel = value?.Name;
                if (tsSockets != null)
                {
                    foreach (SingleControl socket in tsSockets)
                    {
                        socket.RefreshProduct(value);
                    }
                }
                SetTestSeqFile(value);
            }
        }
        private string currentProductModel;
        public string CurrentProductModel
        {
            get => currentProductModel;
            set
            {
                Set(ref currentProductModel, value);
            }
        }
@@ -119,8 +142,13 @@
            }
        }
        public List<double> FontSizeSource { get; set; } = new List<double> {
            10,11,12,13,14,15,16,17,18,19,20
        };
        private Pie pie;
        private string CountIniPath;
        private bool IsOptRequirePassword;
        private bool alarmVisiable;
        public bool AlarmVisiable
@@ -138,9 +166,12 @@
            get => _enableMes;
            set
            {
                if (WriteConfig("EnableMes", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableMes, value);
                    if (WriteConfig("EnableMes", value))
                    {
                        Set(ref _enableMes, value);
                    }
                }
            }
        }
@@ -164,9 +195,12 @@
            get => _enableDebugMode;
            set
            {
                if (WriteConfig("EnableDebugMode", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableDebugMode, value);
                    if (WriteConfig("EnableDebugMode", value))
                    {
                        Set(ref _enableDebugMode, value);
                    }
                }
            }
        }
@@ -177,9 +211,12 @@
            get => _enableNGPause;
            set
            {
                if (WriteConfig("EnableNGPause", value))
                if (RequirePassword() == true)
                {
                    Set(ref _enableNGPause, value);
                    if (WriteConfig("EnableNGPause", value))
                    {
                        Set(ref _enableNGPause, value);
                    }
                }
            }
        }
@@ -212,11 +249,57 @@
            }
        }
        private bool autoExecuteSeq;
        public bool AutoExecuteSeq
        {
            get => autoExecuteSeq;
            set
            {
                Set(ref autoExecuteSeq, value);
            }
        }
        private string currentWorkorder;
        public string CurrentWorkorder
        {
            get => currentWorkorder;
            set
            {
                if (WriteIni("UI_CurrentWorkorder", value))
                {
                    Set(ref currentWorkorder, value);
                    engine?.Globals.SetValString("StationState.WorkOrder", 1, value);
                    engine?.CommitGlobalsToDisk(promptOnSaveConflicts: false);
                }
            }
        }
        private bool _DisableScanner;
        public bool DisableScanner
        {
            get => _DisableScanner;
            set
            {
                if (WriteConfig("DisableScanner", value))
                {
                    Set(ref _DisableScanner, value);
                }
            }
        }
        private string tsModelPath;
        private string dataLogPath;
        private SqliteHelper sqliteHelper;
        private MQConnector mqConnector;
        private int probeWarn;
        public TsExecution()
        {
            DataContext = this;
            GCTimer = new Timer();
            InitializeComponent();
            InitChart();
            InitTsEngine();
            //初始化TestStand引擎
@@ -229,12 +312,92 @@
            base.SetBaseFolder(folder);
        }
        private void CheckSqlHelper()
        {
            string today = DateTime.Now.ToString("yyyyMMdd");
            string dbPath = Path.Combine(dataLogPath, $"Data_{today}.db");
            if (!File.Exists(dbPath))
            {
                SqliteHelper.CreateDatabase(dbPath);
            }
            if (sqliteHelper == null || sqliteHelper.DataBaseFile != dbPath)
            {
                sqliteHelper?.Dispose();
                sqliteHelper = new SqliteHelper(dbPath);
                sqliteHelper.ExecuteSql(@"CREATE TABLE IF NOT EXISTS serialData (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    step TEXT NOT NULL,
                    position TEXT,
                    limitDown TEXT,
                    limitUp TEXT,
                    unit TEXT,
                    offset TEXT,
                    value TEXT,
                    status TEXT,
                    finalStatus TEXT,
                    consumeTime TEXT,
                    totalConsumeTime TEXT,
                    time DATETIME NOT NULL);");
                sqliteHelper.ExecuteSql(@"CREATE TABLE IF NOT EXISTS testResult (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    position TEXT,
                    status TEXT,
                    result TEXT NOT NULL,
                    time DATETIME NOT NULL);");
            }
        }
        public override void InitFinish()
        {
            this.ReadCount(out int pass, out int fail);
            this.DisplayCount(pass, fail);
            ReadConfig();
            InitProducts();
            CheckSqlHelper();
            base.InitFinish();
            if (ParamSetting.EnableAutoModel)
            {
                selectModelPanel.Visibility = Visibility.Collapsed;
                autoModelPanel.Visibility = Visibility.Visible;
                CurrentProductModel = string.Empty;
            }
            try
            {
                UserInfo user = UserInfo.User;
                CurrentUserCode = user?.Code;
                engine?.Globals.SetValString("StationState.OPID", 1, CurrentUserCode);
                engine?.CommitGlobalsToDisk(promptOnSaveConflicts: false);
            }
            catch (Exception ex)
            {
                log.Warn("Get Login User Failed.", ex);
            }
        }
        private void InitMQ()
        {
            mqConnector = new MQConnector("UI");
            mqConnector.BeginReceive(HandleMQUI);
        }
        void HandleMQUI(string msg)
        {
            string[] arr = msg.Split('|');
            int eventCode = int.Parse(arr[0]);
            int index = int.Parse(arr[1]);
            string strData = arr[2];
            Dispatcher.BeginInvoke(new Action(() =>
            {
                HandleUIMessage(eventCode, index, strData);
            }));
        }
        /// <summary>
@@ -244,7 +407,7 @@
        {
            pieChart.Plot.Axes.Frameless();
            pieChart.Plot.HideGrid();
            pieChart.Plot.DataBackground.Color = Colors.Transparent;
            pieChart.Plot.DataBackground.Color = ScottPlot.Colors.Transparent;
            var legend = pieChart.Plot.ShowLegend(Alignment.UpperRight);
            legend.Alignment = Alignment.UpperRight;
@@ -254,10 +417,10 @@
            pieChart.Plot.Font.Automatic();
            List<PieSlice> slices = new List<PieSlice> {
    new PieSlice() { Value = 5, FillColor = Colors.Green,
    new PieSlice() { Value = 5, FillColor = ScottPlot.Colors.Green,
        LabelFontSize = (float)WidthSizeConverter.CountFontSize(20,300,300),
        Label = "Pass",LegendText="Pass" },
    new PieSlice() { Value = 2, FillColor = Colors.Red,
    new PieSlice() { Value = 2, FillColor = ScottPlot.Colors.Red,
        LabelFontSize = (float)WidthSizeConverter.CountFontSize(20,300,300),
        Label = "Fail",LegendText="Fail" } };
@@ -265,32 +428,40 @@
            pie = pieChart.Plot.Add.Pie(slices);
        }
        private bool? RequirePassword()
        {
            if (!IsOptRequirePassword) return true;
            var win = new RequirePasswordWindow
            {
                Owner = Window.GetWindow(this)
            };
            return win.ShowDialog();
        }
        private void InitProducts()
        {
            Products = ProductManager.GetProducts<ObservableCollection<ProductData>>();
            if (Products != null && Products.Count > 0)
            {
                List<ParameterData> parameters =
                    ParameterManager.GetCommonParameter<List<ParameterData>>();
                string tmpNum = parameters?.FirstOrDefault(p => p.Name == "SocketNum")?.Value?.ToString();
                if (!string.IsNullOrEmpty(tmpNum))
                {
                    this.socketNum = Convert.ToInt32(tmpNum);
                }
                string lastModel = engine?.Globals.GetValString("StationState.ProductModel", 1);
                var tempProduct = Products[0];
                if (!string.IsNullOrEmpty(lastModel))
                {
                    var product = Products.FirstOrDefault(p => p.Name == lastModel);
                    if (product != null)
                    {
                        SelectedProduct = product;
                        RefershUI();
                        return;
                        tempProduct = product;
                    }
                }
                SelectedProduct = Products[0];
                RefershUI();
                SelectedProduct = tempProduct;
            }
            RefershUI();
            if (tsSockets != null)
            {
                foreach (SingleControl socket in tsSockets)
                {
                    socket.RefreshProduct(SelectedProduct);
                }
            }
            SampleStatus = false;
        }
@@ -316,111 +487,164 @@
        /// </summary>
        private void InitTsEngine()
        {
            AxApplicationMgr = new AxApplicationMgr();
            AxApplicationMgr.ExitApplication += new EventHandler(this.AxApplicationMgr_ExitApplication);
            AxApplicationMgr.UIMessageEvent +=
                new _ApplicationMgrEvents_UIMessageEventEventHandler(this.AxApplicationMgr_UIMessageEvent);
            AxApplicationMgr.ExecutionClosed +=
                new _ApplicationMgrEvents_ExecutionClosedEventHandler(this.AxApplicationMgr_ExecutionClosed);
            AxApplicationMgr = TestAppManager.GetAxApplicationMgr();
            //AxApplicationMgr. += AxApplicationMgr_EndExecution;
            AxApplicationMgr.EndExecution += AxApplicationMgr_EndExecution;
            AxApplicationMgr.ExitApplication += this.AxApplicationMgr_ExitApplication;
            AxApplicationMgr.UIMessageEvent += this.AxApplicationMgr_UIMessageEvent;
            AxApplicationMgr.ExecutionClosed += this.AxApplicationMgr_ExecutionClosed;
            ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).BeginInit();
            host.Child = AxApplicationMgr;
            ((System.ComponentModel.ISupportInitialize)(AxApplicationMgr)).EndInit();
        }
        private volatile bool canSwitchModel = false;
        private volatile Action switchAction = null;
        private void AxApplicationMgr_EndExecution(object sender, _ApplicationMgrEvents_EndExecutionEvent e)
        {
            log.Info("AxApplicationMgr_EndExecution");
            if (ReleaseSequenceFile())
            {
                IsTesting = false;
                log.Info("Release SeqFile Success!");
                if (canSwitchModel) switchAction?.Invoke();
            }
            else
            {
                log.Warn("Release SeqFile Fail!");
            }
        }
        /// <summary>
        /// 进程结束事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AxApplicationMgr_ExecutionClosed(object sender, _ApplicationMgrEvents_ExecutionClosedEvent e)
        {
            //ReleaseSequenceFile();
        }
        private void PluginControl_Loaded(object sender, RoutedEventArgs e)
        {
            new MaskWindow((WindowX)Window.GetWindow(this),
                (win) =>
            ShowMask(() =>
            {
                try
                {
                    try
                    {
                        Dispatcher.Invoke(() =>
                        {
                            try
                            {
                                UserInfo user = UserInfo.User;
                                CurrentUserCode = user?.Code;
                            }
                            catch (Exception ex)
                            {
                                log.Warn("Get Login User Failed.", ex);
                            }
                            ReadConfig();
                        });
                        isLoadOK = true;
                        StartSequence();
                    }
                    catch (Exception ex)
                    {
                        log.Error("TsExecution Loaded Failed.", ex);
                        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
                    }
                    try
                    {
                        if (Environment.Version.ToString() != this.AxApplicationMgr.GetEngine().DotNetCLRVersion)
                            this.GCTimer.Enabled = true;
                    }
                    catch (Exception ex)
                    {
                        log.Error("TsExecution GCTimer Start Failed", ex);
                        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.LoadFailed")}: {ex.Message}");
                    }
                    Dispatcher.Invoke(() =>
                    {
                        if (isLoadOK) Loaded -= PluginControl_Loaded;
                    });
                    //Dispatcher.Invoke(() =>
                    //{
                    //    try
                    //    {
                    //        ReadConfig();
                    //        //连接OPChandle
                    //        //this.OpcHandle.Connect2("127.0.0.1", 6543, 18081, out string ErrMsg, null);
                    //        isLoadOK = true;
                    //        //启动测试进程
                    //        StartSequence();
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        log.Error("TsExecution Loaded Failed.", ex);
                    //        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
                    //    }
                    //});
                    isLoadOK = true;
                    if (AutoExecuteSeq) StartSequence();
                }
                ).Info(LangUtil.Get("App.UsercontrolIsLoading"));
                catch (Exception ex)
                {
                    log.Error("TsExecution Loaded Failed.", ex);
                    MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
                }
                try
                {
                    if (Environment.Version.ToString() != this.AxApplicationMgr.GetEngine().DotNetCLRVersion)
                        this.GCTimer.Enabled = true;
                }
                catch (Exception ex)
                {
                    log.Error("TsExecution GCTimer Start Failed", ex);
                    MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.LoadFailed")}: {ex.Message}");
                }
                Dispatcher.Invoke(() =>
                {
                    if (isLoadOK) Loaded -= PluginControl_Loaded;
                });
            }, (ex) =>
            {
                ToastHelper.Error("Loaded Failed.");
                log.Error("Loaded Error.", ex);
            }, null, LangUtil.Get("App.UsercontrolIsLoading"));
            //new MaskWindow((WindowX)Window.GetWindow(this),
            //    (win) =>
            //    {
            //        try
            //        {
            //            Dispatcher.Invoke(() =>
            //            {
            //                try
            //                {
            //                    UserInfo user = UserInfo.User;
            //                    CurrentUserCode = user?.Code;
            //                }
            //                catch (Exception ex)
            //                {
            //                    log.Warn("Get Login User Failed.", ex);
            //                }
            //            });
            //            isLoadOK = true;
            //            if (AutoExecuteSeq) StartSequence();
            //        }
            //        catch (Exception ex)
            //        {
            //            log.Error("TsExecution Loaded Failed.", ex);
            //            MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.UserControlLoadFailed")}: {ex.Message}");
            //        }
            //        try
            //        {
            //            if (Environment.Version.ToString() != this.AxApplicationMgr.GetEngine().DotNetCLRVersion)
            //                this.GCTimer.Enabled = true;
            //        }
            //        catch (Exception ex)
            //        {
            //            log.Error("TsExecution GCTimer Start Failed", ex);
            //            MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.LoadFailed")}: {ex.Message}");
            //        }
            //        Dispatcher.Invoke(() =>
            //        {
            //            if (isLoadOK) Loaded -= PluginControl_Loaded;
            //        });
            //    }
            //    ).Info(LangUtil.Get("App.UsercontrolIsLoading"));
        }
        private void RefershUI()
        {
            ParameterData p = ParameterManager.GetCommonParameterByName("ProbeWarn");
            int ProbeWarn = 0;
            if (p != null)
            {
                try
                {
                    ProbeWarn = Convert.ToInt32(p.Value);
                }
                catch
                {
                    ProbeWarn = 0;
                }
            }
            panel.Children.Clear();
            string[] names = ParamSetting.SocketNames.Split(',');
            //重新生成子面板
            for (int i = 0; i < this.socketNum; i++)
            {
                SingleControl control = new SingleControl(i, CountIniPath, ProbeWarn);
                string name = string.Empty;
                if (i < names.Length)
                {
                    name = names[i];
                }
                SingleControl control = new SingleControl(i, CountIniPath, this.probeWarn)
                {
                    SocketName = name
                };
                panel.Children.Add(control);
                tsSockets.Add(control);
                //createChildInNewThread(i, CountIniPath, ProbeWarn);
            }
            if (tsSockets.Count == 1)
            {
                panel.Columns = 1;
            }
            else if (tsSockets.Count > 0 && (tsSockets.Count % 3) == 0)
            {
                panel.Columns = 3;
            }
            else
            {
@@ -440,7 +664,7 @@
                this.AxApplicationMgr.IsEditor = true;
                this.AxApplicationMgr.LoginOnStart = false;
                this.AxApplicationMgr.Start();
                this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
                //this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
            }
            catch (Exception ex)
            {
@@ -457,6 +681,9 @@
        {
            pass = Convert.ToInt32(IniFileHelper.ReadIniData("Count", "Pass", "0", CountIniPath));
            fail = Convert.ToInt32(IniFileHelper.ReadIniData("Count", "Fail", "0", CountIniPath));
            var fontSize = Convert.ToDouble(IniFileHelper.ReadIniData("Config", "TableFontSize", "12", CountIniPath));
            this.Resources["tableFontSize"] = 20d;
            //CbFontSize.SelectedItem = fontSize;
        }
        private string csvDir;
@@ -469,28 +696,117 @@
        private void ReadConfig()
        {
            ParameterData value;
            bool flag = false;
            try
            {
                value = ParameterManager.GetCommonParameterByName("EnableMes");
                _enableMes = bool.Parse(value.Value);
                Set("EnableMes");
                value = ParameterManager.GetCommonParameterByName("DefaultEnableMes");
                if (value != null)
                {
                    flag = bool.Parse(value.Value);
                }
            }
            catch
            {
                _enableMes = false;
                Set("EnableMes");
                flag = false;
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("SocketNum");
                if (value != null)
                {
                    this.socketNum = int.Parse(value.Value);
                }
            }
            catch
            {
                this.socketNum = 2;
            }
            if (flag)
            {
                EnableMes = true;
            }
            else
            {
                try
                {
                    value = ParameterManager.GetCommonParameterByName("EnableMes");
                    if (value == null)
                    {
                        CbEnableMes.Visibility = Visibility.Collapsed;
                    }
                    else
                    {
                        _enableMes = bool.Parse(value.Value);
                        Set("EnableMes");
                    }
                }
                catch
                {
                    _enableMes = false;
                    Set("EnableMes");
                }
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("EnableNGPause");
                _enableNGPause = bool.Parse(value.Value);
                Set("EnableNGPause");
                if (value == null)
                {
                    CbEnableNGPause.Visibility = Visibility.Collapsed;
                }
                else
                {
                    _enableNGPause = bool.Parse(value.Value);
                    Set("EnableNGPause");
                }
            }
            catch
            {
                _enableNGPause = false;
                Set("EnableNGPause");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("EnableDebugMode");
                if (value == null)
                {
                    CbEnableDebugMode.Visibility = Visibility.Collapsed;
                }
                else
                {
                    _enableDebugMode = bool.Parse(value.Value);
                    Set("EnableDebugMode");
                }
            }
            catch
            {
                _enableDebugMode = false;
                Set("EnableDebugMode");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("DisableScanner");
                if (value == null)
                {
                    CbDisableScanner.Visibility = Visibility.Collapsed;
                }
                else
                {
                    _DisableScanner = bool.Parse(value.Value);
                    Set("DisableScanner");
                }
            }
            catch
            {
                _DisableScanner = false;
                Set("DisableScanner");
            }
            try
@@ -505,22 +821,18 @@
                Set("EnableCanLog");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("EnableDebugMode");
                _enableDebugMode = bool.Parse(value.Value);
                Set("EnableDebugMode");
            }
            catch
            {
                _enableDebugMode = false;
                Set("EnableDebugMode");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("EnableSimpleMode");
                EnableSimpleMode = bool.Parse(value.Value);
                if (value == null)
                {
                    CbEnableSimpleMode.Visibility = Visibility.Collapsed;
                }
                else
                {
                    EnableSimpleMode = bool.Parse(value.Value);
                }
            }
            catch
            {
@@ -530,11 +842,28 @@
            try
            {
                value = ParameterManager.GetCommonParameterByName("UI_ShowInfoDock");
                UI_ShowInfoDock = bool.Parse(value.Value);
                if (value == null)
                {
                    CbUI_ShowInfoDock.Visibility = Visibility.Collapsed;
                }
                else
                {
                    UI_ShowInfoDock = bool.Parse(value.Value);
                }
            }
            catch
            {
                UI_ShowInfoDock = false;
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("AutoExecuteSeq");
                AutoExecuteSeq = bool.Parse(value.Value);
            }
            catch
            {
                AutoExecuteSeq = true;
            }
            try
@@ -552,25 +881,73 @@
                csvDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestReport");
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("IsOptRequirePassword");
                IsOptRequirePassword = bool.Parse(value.Value);
            }
            catch
            {
                IsOptRequirePassword = false;
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("UI_CurrentWorkorder");
                CurrentWorkorder = value.Value;
            }
            catch
            {
                CurrentWorkorder = string.Empty;
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("TS_ShowTitleWorkorder");
                var boo = bool.Parse(value.Value);
                if (boo)
                {
                    workorderPanel.Visibility = Visibility.Visible;
                }
            }
            catch
            {
            }
            dataLogPath = ParamSetting.DataLogFolder;
            try
            {
                value = ParameterManager.GetCommonParameterByName("TsModelPath");
                tsModelPath = value?.Value ?? @"C:\Users\Public\Documents\National Instruments\TestStand 2020 (64-bit)\Components\Models\ParallelModel.seq";
            }
            catch
            {
                //@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq"
                tsModelPath = @"C:\Users\Public\Documents\National Instruments\TestStand 2020 (64-bit)\Components\Models\ParallelModel.seq";
            }
            try
            {
                value = ParameterManager.GetCommonParameterByName("ProbeWarn");
                probeWarn = int.Parse(value?.Value);
            }
            catch
            {
                probeWarn = 0;
            }
            //Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableMes", "true", CountIniPath));
            //EnableCanLog = Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableCanLog", "true", CountIniPath));
            //EnableDebugMode = Convert.ToBoolean(IniFileHelper.ReadIniData("Config", "EnableDebugMode", "true", CountIniPath));
        }
        //private void WriteToTsWhenInit()
        //{
        //    foreach (var ts in tsSockets)
        //    {
        //        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.EnableMes", 1, EnableMes);
        //        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.EnableNGPause", 1, EnableNGPause);
        //        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.EnableCanLog", 1, EnableCanLog);
        //        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.EnableDebugMode", 1, EnableDebugMode);
        //    }
        //}
        private bool WriteConfig(string name, bool value)
        {
            //IniFileHelper.WriteIniData("Config", name, value.ToString(), CountIniPath);
            try
            {
                if (ParameterManager.UpdateCommonParameter(name, value, out string errMsg))
@@ -578,7 +955,33 @@
                    foreach (var ts in tsSockets)
                    {
                        ts?.SequenceFileContext?.StationGlobals.SetValBoolean($"SystemSetting.{name}", 1, value);
                        if (ts?.SequenceFileContext?.Sequence != null)
                        {
                            ts.SequenceFileContext.Sequence.FailureAction =
                                value ? FailureActions.FailureAction_None : FailureActions.FailureAction_GotoCleanup;
                        }
                    }
                    return true;
                }
                else
                {
                    throw new Exception(errMsg);
                }
            }
            catch (Exception ex)
            {
                MsgBoxHelper2.Error(ex.Message);
                return false;
            }
        }
        private bool WriteIni(string name, object value)
        {
            //IniFileHelper.WriteIniData("Config", name, value.ToString(), CountIniPath);
            try
            {
                if (ParameterManager.UpdateCommonParameter(name, value, out string errMsg))
                {
                    return true;
                }
                else
@@ -658,62 +1061,79 @@
        /// </summary>
        private void StartSequence()
        {
            log.Info($"Start ATE Seq isLoadOK:{isLoadOK}");
            if (!isLoadOK) return;
            //MaskWindow mask = new MaskWindow();
            try
            {
                engine?.Globals.SetValString("StationState.ProductModel", 1, SelectedProduct?.Name);
                engine?.CommitGlobalsToDisk(promptOnSaveConflicts: false);
                this.modeSeq = this.engine.GetSequenceFileEx(@"C:\Program Files\National Instruments\TestStand 2020\Components\Models\TestStandModels\ParallelModel.seq");
                this.testSeq = this.engine.GetSequenceFileEx(this.testSeqFile, 0, TypeConflictHandlerTypes.ConflictHandler_UseGlobalType);
                //var sb = testSeq.GetSequenceByName("MainSequence");
                //sb.
                this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null);
                IsTesting = true;
                engine?.Globals.SetValBoolean("StationState.StopTest", 1, false);
            }
            catch (Exception ex)
            {
                Dispatcher.Invoke(() =>
                {
                    log.Error("Start Sequence Failed.", ex);
                    MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}");
                });
                log.Error("Reset StopTest Failed.", ex);
            }
            finally
            if (ParamSetting.EnableAutoModel)
            {
                try
                {
                    var path = ParameterManager.GetCommonParameterByName<string>("CommonMainSeq", "");
                    if (string.IsNullOrEmpty(path))
                    {
                        Dispatcher.Invoke(() =>
                        {
                            MsgBoxHelper.Error(this, $"请先设置CommonMainSeq参数");
                        });
                        return;
                    }
                    this.testSeqFile = path;
                    this.modeSeq = this.engine.GetSequenceFileEx(tsModelPath);
                    this.testSeq = this.engine.GetSequenceFileEx(this.testSeqFile, 2, TypeConflictHandlerTypes.ConflictHandler_UseGlobalType);
                    this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null);
                    IsTesting = true;
                }
                catch (Exception ex)
                {
                    Dispatcher.Invoke(() =>
                    {
                        log.Error("Start Sequence Failed.", ex);
                        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}");
                    });
                }
            }
            else
            {
                //MaskWindow mask = new MaskWindow();
                try
                {
                    engine?.Globals.SetValString("StationState.ProductModel", 1, CurrentProductModel);
                    engine?.CommitGlobalsToDisk(promptOnSaveConflicts: false);
                    this.modeSeq = this.engine.GetSequenceFileEx(tsModelPath);
                    this.testSeq = this.engine.GetSequenceFileEx(this.testSeqFile, 2, TypeConflictHandlerTypes.ConflictHandler_UseGlobalType);
                    this.execution = this.engine.NewExecution(this.testSeq, "Test UUTs", this.modeSeq, false, 0, null, null, null);
                    IsTesting = true;
                }
                catch (Exception ex)
                {
                    Dispatcher.Invoke(() =>
                    {
                        log.Error("Start Sequence Failed.", ex);
                        MsgBoxHelper.Error(this, $"{LangUtil.Get("Ts.StartSequenceFail")}: {ex.Message}");
                    });
                }
                finally
                {
                }
            }
        }
        public void StopSequenceClick()
        {
            new MaskWindow((WindowX)Window.GetWindow(this),
                    (win) =>
                    {
                        try
                        {
                            bool stoped = StopSequence();
                            if (stoped)
                            {
                                IsTesting = false;
                            }
                        }
                        finally
                        {
                            Dispatcher.Invoke(() =>
                            {
                                win.Close();
                            });
                        }
                        //Dispatcher.Invoke(() =>
                        //{
                        //});
                    }
                    ).Info(LangUtil.Get("App.SequenceIsStopping"));
            canSwitchModel = false;
            switchAction = null;
            ShowMask(() =>
            {
                bool stoped = StopSequence();
            }, null, null, LangUtil.Get("App.SequenceIsStopping"));
        }
        /// <summary>
@@ -723,22 +1143,22 @@
        {
            try
            {
                if (this.tsSockets.Count > 0)
                {
                    for (int i = 0; i < tsSockets.Count; i++)
                    {
                        var context = this.tsSockets[i].SequenceFileContext;
                        //bool val = context.StationGlobals.Exists("StationState.StopTest", 0);
                        //if (val)
                        //{
                        //    context.StationGlobals.SetValBoolean("StationState.StopTest", 0, true);
                        //    bool isStop = this.execution.WaitForEndEx(2000, true, null, null);
                        //}
                        context?.StationGlobals.SetValBoolean("StationState.StopTest", 1, true);
                    }
                }
                //if (this.tsSockets.Count > 0)
                //{
                //    for (int i = 0; i < tsSockets.Count; i++)
                //    {
                //        var context = this.tsSockets[i].SequenceFileContext;
                //        context?.StationGlobals.SetValBoolean("StationState.StopTest", 1, true);
                //    }
                //}
                engine.Globals.SetValBoolean("StationState.StopTest", 1, true);
                if (this.execution == null) return true;
                return this.execution.WaitForEndEx(2000, true, null, null);
                //bool res = this.execution.WaitForEndEx(-1, true, null, null);
                bool res = this.execution?.WaitForEndEx(-1, true, Type.Missing, null) == true;
                Marshal.ReleaseComObject(this.execution);
                this.execution = null;
                return res;
            }
            catch (Exception ex)
            {
@@ -772,21 +1192,29 @@
        private void StartClick()
        {
            new MaskWindow(Window.GetWindow(this),
                (win) =>
                {
                    try
                    {
                        StartSequence();
                    }
                    finally
                    {
                        win.Dispatcher.Invoke(() =>
                        {
                            win.Close();
                        });
                    }
                }).Info(LangUtil.Get("Ts.SequenceIsStarting"));
            canSwitchModel = true;
            ShowMask(() =>
            {
                StartSequence();
            }, null, null, LangUtil.Get("Ts.SequenceIsStarting"));
            //new MaskWindow(Window.GetWindow(this),
            //    (win) =>
            //    {
            //        try
            //        {
            //            StartSequence();
            //        }
            //        catch (Exception ex) {
            //        }
            //        finally
            //        {
            //            win.Dispatcher.Invoke(() =>
            //            {
            //                win.Close();
            //            });
            //        }
            //    }).Info(LangUtil.Get("Ts.SequenceIsStarting"));
        }
        /// <summary>
@@ -798,30 +1226,6 @@
        {
            //Environment.ExitCode = this.AxApplicationMgr.ExitCode;
            //this.Close();
        }
        /// <summary>
        /// 进程结束事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AxApplicationMgr_ExecutionClosed(object sender, _ApplicationMgrEvents_ExecutionClosedEvent e)
        {
            try
            {
                if (this.testSeq == null)
                    return;
                this.engine.ReleaseSequenceFileEx(this.testSeq, 0);
                this.engine.ReleaseSequenceFileEx(this.modeSeq, 0);
                this.engine.UnloadAllModules();
                this.testSeq = null;
                this.modeSeq = null;
            }
            catch (Exception ex)
            {
                log.Error("ReleaseSequenceFileEx Failed.", ex);
                MsgBoxHelper.Error(Window.GetWindow(this), $"{LangUtil.Get("Ts.ReleaseSequenceFileFail")}: {ex.Message}");
            }
        }
        public void UpdatePositionStatus(int index, string status)
@@ -847,18 +1251,254 @@
                TestItems[4], TestItems[5], TestItems[6]);
        }
        public void SetPositionBarcode(int index, string barcode)
        public void SetPositionBarcode(int index, string strData)
        {
            this.tsSockets[index].Barcode = barcode;
            if (strData.Contains(";"))
            {
                var strs = strData.Split(';');
                this.tsSockets[index].Barcode = strs[0];
                this.tsSockets[index].Model = strs[1];
            }
            else
            {
                this.tsSockets[index].Barcode = strData;
            }
        }
        public void SavePositionCSV(int index)
        public void SavePositionCSV(int index, string csvPath)
        {
            //var time = DateTime.Now;
            //string status = this.tsSockets[index].Status == "Passed" ? "PASS" : "FAIL";
            //string csvPath = Path.Combine(csvDir, SelectedProduct?.Name ?? "未知产品", time.ToString("yyyyMMdd"), status,
            //    $"{this.tsSockets[index].Barcode}-{time.ToString("HHmmss")}.csv");
            this.tsSockets[index].WriteToCSV(csvPath);
        }
        public void SaveTemplateCSV(int index)
        {
            var time = DateTime.Now;
            string status = this.tsSockets[index].Status == "Passed" ? "PASS" : "FAIL";
            string csvPath = Path.Combine(csvDir, SelectedProduct?.Name ?? "未知产品", time.ToString("yyyyMMdd"), status,
                $"{this.tsSockets[index].Barcode}-{time.ToString("HHmmss")}.csv");
            string csvPath = Path.Combine(csvDir, CurrentProductModel ?? "未知产品", time.ToString("yyyyMMdd"), status, $"{this.tsSockets[index].Barcode}-{time.ToString("HHmmss")}.csv");
            this.tsSockets[index].WriteToCSV(csvPath);
        }
        public void SavePositionDB(int index, string status)
        {
            CheckSqlHelper();
            var socket = this.tsSockets[index];
            var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            string snr = socket.Barcode;
            string model = CurrentProductModel;
            List<string> sqls = new List<string>();
            foreach (var data in socket.Datasource)
            {
                sqls.Add($@"INSERT INTO serialData (sn,model,station,step,position,limitDown,limitUp,unit,value,status,finalStatus,consumeTime,totalConsumeTime,time) VALUES
('{snr}','{model}','','{data.Name}','{index}','{data.LimitDown}','{data.LimitUp}','{data.Unit}','{data.Value}','{data.Result}','{socket.Status}','{data.ConsumeTime}','{socket.ElapseTime}','{time}')");
            }
            sqls.Add($@"INSERT INTO testResult (sn,model,station,result,time,position,status) VALUES
('{snr}','{model}','','{socket.Status}','{time}','{index}','{status}')");
            sqliteHelper.ExecuteBatchSql(sqls);
        }
        private void HandleUIMessage(int eventCode, int index, string strData)
        {
            switch (eventCode)
            {
                case 10002://更新测试状态
                    string status = strData;
                    UpdatePositionStatus(index, status);
                    break;
                case 10003://发送测试数据
                    AddTestData(index, strData);
                    break;
                case 10004://发送测试过程信息
                    this.tsSockets[index].CurrentStep = strData;
                    break;
                case 10005://初始化测试数据,清空测试数据
                    this.tsSockets[index].IniTestData();
                    break;
                case 10006://发送产品条码
                    SetPositionBarcode(index, strData);
                    break;
                case 10007://开始测试计时
                    tsSockets[index].ElapseTime = "Start Timing";
                    BtnStopSeq.IsEnabled = false;
                    break;
                case 10008://停止测试计时
                    tsSockets[index].ElapseTime = "Stop Timing";
                    BtnStopSeq.IsEnabled = true;
                    break;
                case 10009:
                    //
                    break;
                case 10010:
                    //PropertyObj.SetValBoolean("Locals.MD5_Used", 0, true);
                    //PropertyObj.SetValVariant("FileGlobals.MD5_Value", 0, MD5_DATA);
                    //PropertyObj.SetValVariant("StationGlobals.MD5", 0, MD5_DATA);
                    break;
                case 10011:
                    // write model
                    break;
                case 10012:
                    // read model
                    break;
                case 10013:
                    // read continue
                    break;
                case 10014:
                    break;
                case 10015:
                    break;
                case 10016://显示3D拼接图片
                    break;
                case 10017://更新测试计时,针对部分计时有PLC完成的项目
                    this.tsSockets[index].ElapseTime = strData;
                    break;
                case (int)UIMessageCodes.UIMsg_EndExecution://执行结束
                    //IsTesting = false;
                    //this.ReleaseSequenceFile();
                    break;
                case 10030://显示测试进度
                    int ProcessVal = Convert.ToInt32(strData);
                    this.tsSockets[index].SetTestProcess(ProcessVal);
                    break;
                case 10031://导出CSV
                    if (string.IsNullOrEmpty(strData))
                    {
                        SaveTemplateCSV(index);
                        return;
                    }
                    try
                    {
                        string[] datas = strData.Split(';');
                        SavePositionCSV(index, datas[0]);
                        if (datas.Length >= 2)
                        {
                            SavePositionDB(index, datas[1]);
                        }
                        else
                        {
                            var sss = this.tsSockets[index].Status;
                            SavePositionDB(index, sss);
                        }
                    }
                    catch (Exception ex)
                    {
                        log.Warn("10031 Error.", ex);
                        SaveTemplateCSV(index);
                    }
                    break;
                case 10032://按下标暂停测试
                    this.tsSockets[index].ShowPausePanel();
                    break;
                case 10033:
                    var alarm = new AlarmText
                    {
                        VirtualId = DateTime.Now.ToString("yyyyMMddHHmmssfff"),
                        AlarmInfo = strData
                    };
                    ShowAlarm(alarm);
                    break;
                case 10034:
                    CurrentProductModel = strData;
                    break;
                case 10035:
                    string[] arr_10035 = strData.Split(';');
                    int[][] points = new int[arr_10035.Length - 1][];
                    for (int i = 1; i < arr_10035.Length; i++)
                    {
                        string[] strs = arr_10035[i].Split(',');
                        points[i - 1] = new int[2] { int.Parse(strs[0]), int.Parse(strs[1]) };
                    }
                    this.tsSockets[index].DrawScreenPoints(int.Parse(arr_10035[0]), points);
                    break;
                case 10036:
                    this.tsSockets[index].ClearScreenPoint(int.Parse(strData));
                    break;
                case 10099:
                    string[] arr = strData.Split(',');
                    if (canSwitchModel) SwitchSequenceByModel(index, arr[0], arr[1]);
                    break;
                default:
                    break;
            }
        }
        private void SwitchSequenceByModel(int index, string model, string snr)
        {
            Dispatcher.Invoke(() =>
            {
                var target = Products.FirstOrDefault(e => e.Name == model);
                ShowMask(() =>
                {
                    bool stoped = StopSequence();
                    //if (stoped)
                    //{
                    //    IsTesting = false;
                    //}
                }, null, null, "换型中,请稍后...");
                if (target == null)
                {
                    MsgBoxHelper2.Warn($"请先在产品管理页面配置型号 [{model}] 的产品信息!");
                    return;
                }
                switchAction = () =>
                {
                    switchAction = null;
                    log?.Info($"尝试自动换型: {switchAction}");
                    if (canSwitchModel)
                    {
                        Dispatcher.Invoke(() =>
                        {
                            try
                            {
                                log?.Info("开始自动换型");
                                SelectedProduct = target;
                                engine?.Globals.SetValString($"CacheSNR[{index}]", 1, snr);
                                engine?.CommitGlobalsToDisk(false);
                                StartClick();
                            }
                            catch (Exception ex)
                            {
                                log?.Error("自动换型失败", ex);
                            }
                        });
                    }
                };
            });
        }
        private void ShowAlarm(AlarmText alarm)
        {
            AlarmShowHelper.ShowAlarm(alarm);
            mSMQHelper.Send("Alarm", $"ATE测试 {alarm.AlarmInfo}");
        }
        /// <summary>
@@ -870,113 +1510,26 @@
        {
            try
            {
                int EventCase = Convert.ToInt32(e.uiMsg.Event);
                int Index = Convert.ToInt16(e.uiMsg.NumericData);//SocketIndex
                int eventCode = Convert.ToInt32(e.uiMsg.Event);
                int index = Convert.ToInt16(e.uiMsg.NumericData);//SocketIndex
                string strData = e.uiMsg.StringData;
                try
                {
                    log.Info($"Event: {EventCase}, NumericData: {Index}, StringData: {strData}");
                    log.Debug($"Event: {eventCode}, NumericData: {index}, StringData: {strData}");
                }
                catch
                {
                }
                switch (EventCase)
                if (eventCode == 10001)
                {
                    case 10001://传递SocketContext
                        tsSockets[Index].SequenceFileContext = (SequenceContext)e.uiMsg.ActiveXData;
                        break;
                    sequenceContext = (SequenceContext)e.uiMsg.ActiveXData;
                    case 10002://更新测试状态
                        string status = e.uiMsg.StringData;
                        UpdatePositionStatus(Index, status);
                        break;
                    case 10003://发送测试数据
                        AddTestData(Index, e.uiMsg.StringData);
                        break;
                    case 10004://发送测试过程信息
                        this.tsSockets[Index].CurrentStep = e.uiMsg.StringData;
                        break;
                    case 10005://初始化测试数据,清空测试数据
                        this.tsSockets[Index].IniTestData();
                        break;
                    case 10006://发送产品条码
                        SetPositionBarcode(Index, e.uiMsg.StringData);
                        break;
                    case 10007://开始测试计时
                        tsSockets[Index].ElapseTime = "Start Timing";
                        BtnStopSeq.IsEnabled = false;
                        break;
                    case 10008://停止测试计时
                        tsSockets[Index].ElapseTime = "Stop Timing";
                        BtnStopSeq.IsEnabled = true;
                        break;
                    case 10009:
                        //
                        break;
                    case 10010:
                        //PropertyObj.SetValBoolean("Locals.MD5_Used", 0, true);
                        //PropertyObj.SetValVariant("FileGlobals.MD5_Value", 0, MD5_DATA);
                        //PropertyObj.SetValVariant("StationGlobals.MD5", 0, MD5_DATA);
                        break;
                    case 10011:
                        // write model
                        break;
                    case 10012:
                        // read model
                        break;
                    case 10013:
                        // read continue
                        break;
                    case 10014:
                        break;
                    case 10015:
                        break;
                    case 10016://显示3D拼接图片
                        break;
                    case 10017://更新测试计时,针对部分计时有PLC完成的项目
                        this.tsSockets[Index].ElapseTime = e.uiMsg.StringData;
                        break;
                    case (int)UIMessageCodes.UIMsg_EndExecution://执行结束
                        IsTesting = false;
                        // this.ReleaseSequenceFile();
                        break;
                    case 10030://显示测试进度
                        int ProcessVal = Convert.ToInt32(e.uiMsg.StringData);
                        this.tsSockets[Index].SetTestProcess(ProcessVal);
                        break;
                    case 10031://导出CSV
                        SavePositionCSV(Index);
                        break;
                    case 10032://按下标暂停测试
                        this.tsSockets[Index].ShowPausePanel();
                        break;
                    default:
                        break;
                    tsSockets[index].SequenceFileContext = (SequenceContext)e.uiMsg.ActiveXData;
                    return;
                }
                HandleUIMessage(eventCode, index, strData);
            }
            catch (Exception ex)
            {
@@ -1006,7 +1559,10 @@
            string name = product.Name;
            List<ParameterData> parameters = ProductManager.GetParametersByProductName(name);
            testSeqFile = parameters.FirstOrDefault(p => p.Name == "TestSequence")?.Value?.ToString();
            StartSequence();
            if (AutoExecuteSeq)
            {
                StartSequence();
            }
        }
        private void ClearNum()
@@ -1029,13 +1585,6 @@
            try
            {
                StopSequence();
                // this.engine?.TerminateAll();
                // this.engine?.ReleaseSequenceFileEx(this.testSeq, 0);
                // this.engine?.ReleaseSequenceFileEx(this.modeSeq, 0);
                // this.engine?.UnloadAllModules();
                // this.engine?.ShutDown(true);
                //this.testSeq = null;
                //this.modeSeq = null;
                base.OnClose(sender, e);
            }
            catch (Exception ex)
@@ -1044,9 +1593,102 @@
            }
        }
        public override void DoClose(object sender, EventArgs e)
        {
            base.DoClose(sender, e);
        }
        /// <summary>
        /// 释放所有的序列文件
        /// </summary>
        private bool ReleaseSequenceFile()
        {
            try
            {
                lock (this)
                {
                    if (this.testSeq == null)
                    {
                        return true;
                    }
                    //execution.Abort();
                    int count = 10;
                    while (count > 0)
                    {
                        try
                        {
                            if (this.testSeq == null)
                                return true;
                            if (this.engine?.ReleaseSequenceFileEx(this.testSeq, 4) == true)
                            {
                                Marshal.ReleaseComObject(this.testSeq);
                                this.testSeq = null;
                                // GC.Collect();
                            }
                            if (this.engine?.ReleaseSequenceFileEx(this.modeSeq, 4) == true)
                            {
                                Marshal.ReleaseComObject(this.modeSeq);
                                this.modeSeq = null;
                            }
                            this.engine?.UnloadAllModules();
                            return this.testSeq == null && this.modeSeq == null;
                        }
                        catch (Exception ex)
                        {
                            log.Warn($"ReleaseSequenceFile In {count} Times Fail.", ex);
                            count--;
                            System.Threading.Thread.Sleep(1000);
                        }
                    }
                    log.Warn($"ReleaseSequenceFile Failed.");
                    return false;
                }
            }
            catch (Exception ex)
            {
                log.Warn("ReleaseSequenceFile Error.", ex);
                return false;
            }
        }
        private void PluginControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
        }
        private void CbFontSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                if (e.AddedItems != null && e.AddedItems.Count > 0)
                {
                    var fontSize = (double)e.AddedItems[0];
                    this.Resources["tableFontSize"] = fontSize;
                    IniFileHelper.WriteIniData("Config", "TableFontSize", fontSize.ToString(), CountIniPath);
                }
            }
            catch
            {
            }
        }
        private void Label_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            //workOrderEditor.Focus();
            //workOrderEditor.IsEditing = true;
            if (RequirePassword() == true)
            {
                var win = new WorkOrderWin
                {
                    WorkOrder = CurrentWorkorder,
                    Owner = Window.GetWindow(this)
                };
                if (win.ShowDialog() == true)
                {
                    CurrentWorkorder = win.WorkOrder;
                }
            }
        }
    }
}