From 9d1660270272180cd71147d6ddd53d1382643d2e Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 02 十一月 2026 18:00:14 +0800
Subject: [PATCH] merge: 并入远程 Initial commit 作为历史根节点
---
Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs | 715 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 715 insertions(+), 0 deletions(-)
diff --git a/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
new file mode 100644
index 0000000..fe22156
--- /dev/null
+++ b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
@@ -0,0 +1,715 @@
+锘縰sing CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using GongSolutions.Wpf.DragDrop;
+using HMI.Core.Util;
+using HMI.UI;
+using HMI.UI.Util;
+using log4net;
+using Microsoft.Win32;
+using NationalInstruments.TestStand.Interop.API;
+using Plugin.SeqEditor.Constant;
+using Plugin.SeqEditor.Entity;
+using Plugin.SeqEditor.Util;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Input;
+using System.Windows.Media;
+
+namespace Plugin.SeqEditor.ViewModel
+{
+
+ public partial class SeqEditorViewModel : ObservableObject
+ {
+ private ObservableCollection<StepUI> setupSteps = new ObservableCollection<StepUI>();
+
+ private ObservableCollection<StepUI> mainSteps = new ObservableCollection<StepUI>();
+
+ private ObservableCollection<StepUI> cleanupSteps = new ObservableCollection<StepUI>();
+
+ [ObservableProperty]
+ private ObservableCollection<StepUI> allSteps = new ObservableCollection<StepUI>();
+
+ [ObservableProperty]
+ private ObservableCollection<SeqUI> sequences = new ObservableCollection<SeqUI>();
+
+ [ObservableProperty]
+ private SeqUI currentSeqUI;
+
+ [ObservableProperty]
+ private StepUI currentStepUI;
+
+ [ObservableProperty]
+ private string currentFileName;
+
+ [ObservableProperty]
+ private string currentSeqTitle = LangUtil.Get("se.steps");
+
+ [ObservableProperty]
+ private string targetType = null;
+
+ [ObservableProperty]
+ private string currentFilePath;
+
+ [ObservableProperty]
+ private bool canDrop = true;
+
+ public IDropTarget StepDropHandler { get; set; }
+
+ private Engine engine;
+ private SequenceFile sequenceFile;
+
+ public Dictionary<string, SequenceFile> cacheFiles = new Dictionary<string, SequenceFile>();
+
+ private bool isLoaded;
+ private ILog log;
+ public SeqEditor control { get; private set; }
+
+ public List<ItemData> Types = FilterTypeData.ItemSource;
+
+ private HashSet<string> edits = new HashSet<string>();
+ public Dictionary<Sequence, ObservableCollection<StepUI>> sequenceCache { get; private set; } = new();
+
+ private HashSet<string> indexType = new HashSet<string> {
+ StepTypeStr.PassFailTest,
+ StepTypeStr.NumericLimitTest,
+ StepTypeStr.NI_MultipleNumericLimitTest,
+ StepTypeStr.StringValueTest,
+ StepTypeStr.NI_Wait,
+ StepTypeStr.Action
+ };
+
+ public SeqEditorViewModel(SeqEditor control, ILog log)
+ {
+ this.log = log;
+ this.control = control;
+ engine = new Engine();
+ engine.LoadTypePaletteFilesEx();
+ TargetType = string.Empty;
+ StepDropHandler = new TreeListViewHandler(this);
+ }
+
+ ~SeqEditorViewModel()
+ {
+ if (engine != null)
+ {
+ if (sequenceFile != null)
+ {
+ engine.ReleaseSequenceFileEx(sequenceFile);
+ }
+ foreach (var file in cacheFiles.Values)
+ {
+ engine.ReleaseSequenceFileEx(file);
+ }
+ engine.ShutDown(true);
+ // 涓嶅姞寤舵椂浼氬脊绐梞d
+ //System.Threading.Thread.Sleep(2500);
+ }
+ }
+
+ private ObservableCollection<StepUI> LoadSteps(Sequence seq, string group = null)
+ {
+ //if (sequenceCache.ContainsKey(seq))
+ //{
+ // return sequenceCache[seq];
+ //}
+
+ //setupSteps.Clear();
+ //var steps = new ObservableCollection<StepUI>();
+ //int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
+ //for (int i = 0; i < num; i++)
+ //{
+ // Step step = seq.GetStep(i, StepGroups.StepGroup_Setup);
+ // var ui = new StepUI(step);
+ // if (edits.Contains(ui.Type))
+ // {
+ // setupSteps.Add(ui);
+ // steps.Add(ui);
+ // }
+ //}
+ ////SetupSteps = steps;
+ ////steps = new ObservableCollection<StepUI>();
+ //mainSteps.Clear();
+ //num = seq.GetNumSteps(StepGroups.StepGroup_Main);
+ //for (int i = 0; i < num; i++)
+ //{
+ // Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
+ // var ui = new StepUI(step);
+ // if (edits.Contains(ui.Type))
+ // {
+ // mainSteps.Add(ui);
+ // steps.Add(ui);
+ // }
+ //}
+ ////MainSteps = steps;
+ ////steps = new ObservableCollection<StepUI>();
+ //cleanupSteps.Clear();
+ //num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
+ //for (int i = 0; i < num; i++)
+ //{
+ // Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
+ // var ui = new StepUI(step);
+ // if (edits.Contains(ui.Type))
+ // {
+ // cleanupSteps.Add(ui);
+ // steps.Add(ui);
+ // }
+ //}
+ //AllSteps = steps;
+ //CurrentStepUI = null;
+
+ var steps = new ObservableCollection<StepUI>();
+ StepGroups[] groups = new StepGroups[] { StepGroups.StepGroup_Setup, StepGroups.StepGroup_Main, StepGroups.StepGroup_Cleanup };
+
+ foreach (var stepGroup in groups)
+ {
+ int num = seq.GetNumSteps(stepGroup);
+ for (int i = 0; i < num; i++)
+ {
+ Step step = seq.GetStep(i, stepGroup);
+ var ui = Convert2StepUI(i, step, seq, group);
+ if (ui != null)
+ {
+ steps.Add(ui);
+ }
+ }
+ }
+
+ //int num = seq.GetNumSteps(StepGroups.StepGroup_Main);
+ //for (int i = 0; i < num; i++)
+ //{
+ // Step step = seq.GetStep(i, StepGroups.StepGroup_Main);
+ // var ui = Convert2StepUI(step, seq, group);
+ // if (ui != null)
+ // {
+ // steps.Add(ui);
+ // }
+ //}
+
+ //num = seq.GetNumSteps(StepGroups.StepGroup_Cleanup);
+ //for (int i = 0; i < num; i++)
+ //{
+ // Step step = seq.GetStep(i, StepGroups.StepGroup_Cleanup);
+ // var ui = Convert2StepUI(step, seq, group);
+ // if (ui != null)
+ // {
+ // steps.Add(ui);
+ // }
+ //}
+ sequenceCache[seq] = steps;
+ return steps;
+ }
+
+ private int indexCache = 0;
+
+ private StepUI Convert2StepUI(int index, Step step, Sequence sequence, string group)
+ {
+ var ui = new StepUI(step, sequence);
+ if (edits != null && edits.Count > 0 && !edits.Contains(ui.Type))
+ {
+ return null;
+ }
+
+ if (string.IsNullOrEmpty(group))
+ {
+ if (ui.StepGroup == StepGroups.StepGroup_Setup)
+ {
+ group = "Setup";
+ }
+ else if (ui.StepGroup == StepGroups.StepGroup_Main)
+ {
+ group = "Main";
+ }
+ else if (ui.StepGroup == StepGroups.StepGroup_Cleanup)
+ {
+ group = "Cleanup";
+ }
+ else
+ {
+ group = "Unkown";
+ }
+ }
+ ui.Group = group;
+
+ if (ui.Type == StepTypeStr.SequenceCall)
+ {
+ var po = step.Module.AsPropertyObject();
+ bool useCurFile = po.GetValBoolean("UseCurFile", 0);
+ string sfPath = po.GetValString("SFPath", 0);
+ if (useCurFile || Path.GetFileName(currentFilePath).Equals(sfPath, StringComparison.CurrentCultureIgnoreCase))
+ {
+ string seqName = po.GetValString("SeqName", 0);
+ Sequence sunSequence = sequenceFile.GetSequenceByName(seqName);
+ if (sunSequence == null)
+ {
+ return ui;
+ }
+ ui.Children = LoadSteps(sunSequence, group);
+ }
+ else
+ {
+ string seqName = po.GetValString("SeqName", 0);
+ if (!Path.IsPathRooted(sfPath))
+ {
+ sfPath = Path.Combine(Path.GetDirectoryName(CurrentFilePath), sfPath);
+ }
+ SequenceFile diffSequence = null;
+ try
+ {
+ if (cacheFiles.ContainsKey(sfPath))
+ {
+ diffSequence = cacheFiles[sfPath];
+ }
+ else if (File.Exists(sfPath))
+ {
+ diffSequence = engine.GetSequenceFileEx(sfPath);
+ cacheFiles[sfPath] = diffSequence;
+ }
+ }
+ catch (Exception ex)
+ {
+ log.Warn("Read Diff SubSequence Failed.", ex);
+ }
+ if (diffSequence != null)
+ {
+ Sequence sunSequence = diffSequence.GetSequenceByName(seqName);
+ ui.Children = LoadSteps(sunSequence, group);
+ }
+ }
+ }
+ else
+ {
+ }
+ if (CurrentSeqUI != null)
+ {
+ ui.SettingChanged += CurrentSeqUI.OnStepSettingChanged;
+ }
+ return ui;
+ }
+
+
+ [RelayCommand]
+ private void Loaded()
+ {
+ if (!isLoaded)
+ {
+ }
+ }
+
+ [RelayCommand]
+ private void OpenSeqFile()
+ {
+ OpenFileDialog ofd = new OpenFileDialog()
+ {
+ Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
+ };
+ if (ofd.ShowDialog() == true && DoClose())
+ {
+ control.BackgroundAction(() =>
+ {
+ try
+ {
+ var start = DateTime.Now;
+ CurrentFilePath = ofd.FileName;
+ if (sequenceFile != null)
+ {
+ engine.ReleaseSequenceFileEx(sequenceFile);
+ }
+ sequenceFile = engine.GetSequenceFileEx(CurrentFilePath);
+ Sequence main = sequenceFile.GetSequenceByName("MainSequence");
+ CurrentSeqUI = new SeqUI(main);
+
+ //var seqs = new ObservableCollection<SeqUI>();
+ //for (int i = 0; i < sequenceFile.NumSequences; i++)
+ //{
+ // var tsSequence = sequenceFile.GetSequence(i);
+ // seqs.Add(new SeqUI(tsSequence));
+ //}
+ //Sequences = seqs;
+
+ //if (Sequences != null && Sequences.Count > 0)
+ //{
+ // CurrentSeqUI = Sequences[0];
+ //}
+ log.Info($"Open File [{CurrentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
+ }
+ catch (Exception ex)
+ {
+ log.Error($"Open Sequence Failed.", ex);
+ control.Dispatcher.Invoke(() =>
+ {
+ MsgBoxHelper2.Error(ex.Message);
+ });
+ }
+ }, LangUtil.Get("se.seqIsLoading"));
+ }
+ }
+
+ [RelayCommand]
+ private void SaveSeqFile()
+ {
+ if (sequenceFile == null) return;
+ try
+ {
+ sequenceFile?.Save(CurrentFilePath);
+ CurrentSeqUI.IsChanged = false;
+ foreach (var key in cacheFiles.Keys)
+ {
+ cacheFiles[key]?.Save(key);
+ }
+ ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
+ }
+ catch (Exception ex)
+ {
+ log.Error("Save Sequence File Error.", ex);
+ ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
+ }
+ }
+
+ [RelayCommand]
+ private void SaveToFile()
+ {
+ if (sequenceFile == null) return;
+ try
+ {
+ SaveFileDialog sfd = new SaveFileDialog()
+ {
+ Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
+ };
+ if (sfd.ShowDialog() == true)
+ {
+ sequenceFile.Save(sfd.FileName);
+ CurrentFilePath = sfd.FileName;
+ foreach (var key in cacheFiles.Keys)
+ {
+ cacheFiles[key]?.Save(key);
+ }
+ ToastHelper.Success(LangUtil.Get("App.SaveSuccess"));
+ CurrentSeqUI.IsChanged = false;
+ }
+ }
+ catch (Exception ex)
+ {
+ log.Error("Save Sequence File Error.", ex);
+ ToastHelper.Error($"{LangUtil.Get("App.SaveFailed")}: {ex.Message}");
+ }
+ }
+
+ [RelayCommand]
+ private void Refresh()
+ {
+ if (CurrentSeqUI == null) return;
+ RefreshData();
+ }
+
+ private bool DoClose()
+ {
+ if (CurrentSeqUI?.IsChanged == true)
+ {
+ if (MsgBoxHelper2.WarnChoose(LangUtil.Get("se.makeSureClose"))
+ == System.Windows.MessageBoxResult.OK)
+ {
+ goto DoClose;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ DoClose:
+ if (engine != null && sequenceFile != null)
+ {
+ engine.ReleaseSequenceFileEx(sequenceFile);
+ foreach (var file in cacheFiles.Values)
+ {
+ engine.ReleaseSequenceFileEx(file);
+ }
+ sequenceFile = null;
+ }
+
+ cacheFiles.Clear();
+ setupSteps.Clear();
+ mainSteps.Clear();
+ cleanupSteps.Clear();
+ AllSteps = new();
+ Sequences.Clear();
+ CurrentFilePath = string.Empty;
+ CurrentFileName = string.Empty;
+ CurrentSeqUI = null;
+ CurrentStepUI = null;
+ CurrentSeqTitle = LangUtil.Get("se.steps");
+ sequenceCache.Clear();
+ return true;
+ }
+
+ [RelayCommand]
+ private void CloseSeqFile()
+ {
+ DoClose();
+ }
+
+ [RelayCommand]
+ private void AddStep(string type)
+ {
+ try
+ {
+ var group = CurrentStepUI.step.StepGroup;
+ var targetSequence = CurrentStepUI.sequence;
+
+ ObservableCollection<StepUI> source = sequenceCache[targetSequence];
+ //if (group == StepGroups.StepGroup_Setup)
+ //{
+ // source = setupSteps;
+ //}
+ //else if (group == StepGroups.StepGroup_Main)
+ //{
+ // source = mainSteps;
+ //}
+ //else
+ //{
+ // source = cleanupSteps;
+ //}
+ int index = CurrentStepUI.IndexInSequence;
+ if (index < 0)
+ {
+ return;
+ }
+ Step newStep;
+ switch (type)
+ {
+ case "Tests.PassFail":
+ newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.PassFailTest);
+ newStep.Name = DefaultStepName.PassFailTest;
+ break;
+ case "Tests.NumericLimitTest":
+ newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NumericLimitTest);
+ newStep.Name = DefaultStepName.NumericLimitTest;
+ break;
+ case "Tests.NI_MultipleNumericLimitTest":
+ newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NI_MultipleNumericLimitTest);
+ newStep.Name = DefaultStepName.NI_MultipleNumericLimitTest;
+ break;
+ case "Tests.StringValueTest":
+ newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.StringValueTest);
+ newStep.Name = DefaultStepName.StringValueTest;
+ break;
+ case "Actions.LabVIEW":
+ newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.LabWindows/CVI":
+ newStep = engine.NewStep(AdapterKeyNames.FlexCVIAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.C/C++ DLL":
+ newStep = engine.NewStep(AdapterKeyNames.FlexCAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions..NET":
+ newStep = engine.NewStep(AdapterKeyNames.DotNetAdapterKeyname, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.ActiveX/COM":
+ newStep = engine.NewStep(AdapterKeyNames.AutomationAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.None":
+ newStep = engine.NewStep(AdapterKeyNames.NoneAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.LabVIEW NXG":
+ newStep = engine.NewStep(AdapterKeyNames.LabVIEWNXGAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ case "Actions.Python":
+ newStep = engine.NewStep(AdapterKeyNames.PythonAdapterKeyName, StepTypeStr.Action);
+ newStep.Name = DefaultStepName.Action;
+ break;
+ default:
+ return;
+ }
+ var newUI = new StepUI(newStep, targetSequence);
+
+
+ targetSequence.InsertStep(newStep, index + 1, group);
+ ObservableCollection<StepUI> datasource = sequenceCache[targetSequence];
+ int uiIndex = datasource.IndexOf(CurrentStepUI);
+ datasource.Insert(uiIndex + 1, newUI);
+
+
+ //var newItem = new TreeItemData
+ //{
+ // Level = TreeItemData.Level,
+ // ParentItem = TreeItemData.ParentItem,
+ // ParentItems = TreeItemData.ParentItems,
+ // Data = newUI
+ //};
+ //var parentItem = TreeItemData.ParentItem;
+ //if (parentItem != null)
+ //{
+ // var items = parentItem.Items;
+ // int innerIndex = items.IndexOf(TreeItemData);
+
+
+ // items.Insert(innerIndex + 1, newItem);
+ // TreeItemDataCollection.ResetSubItems(items);
+ //}
+ //int itemIndex = TreeCollection.IndexOf(TreeItemData);
+ //TreeCollection.Insert(itemIndex + TreeItemData.AllSubCount + 1, newItem);
+ }
+ catch (Exception ex)
+ {
+ log.Error("Insert Step Error.", ex);
+ MsgBoxHelper2.Error(ex.Message);
+ }
+ }
+
+ [RelayCommand]
+ private void Sb(RoutedPropertyChangedEventArgs<object> e)
+ {
+ CurrentStepUI = e.NewValue as StepUI;
+ }
+
+ static TreeListViewItem VisualUpwardSearch(DependencyObject source)
+ {
+ while (source != null && !(source is TreeViewItem))
+ source = VisualTreeHelper.GetParent(source);
+
+ return source as TreeListViewItem;
+ }
+
+ [RelayCommand]
+ private void Sb2(MouseButtonEventArgs e)
+ {
+ var item = VisualUpwardSearch(e.OriginalSource as DependencyObject);
+ if (item != null)
+ {
+ item.Focus();
+ e.Handled = true;
+ }
+ }
+
+ [ObservableProperty]
+ private TreeItemData treeItemData;
+
+ public void RefreshView()
+ {
+ CollectionViewSource cvs = control.Resources["TreeGridFilter"] as CollectionViewSource;
+ control.Dispatcher.Invoke(() =>
+ {
+ cvs.View.Refresh();
+ });
+ }
+
+ [ObservableProperty]
+ private TreeItemDataCollection treeCollection = new TreeItemDataCollection();
+
+ public void RefreshData()
+ {
+ indexCache = 0;
+ sequenceCache.Clear();
+ foreach (var file in cacheFiles.Values)
+ {
+ try
+ {
+ engine.ReleaseSequenceFileEx(file);
+ Marshal.ReleaseComObject(file);
+ }
+ catch (Exception ex)
+ {
+ log.Error("RefreshData Release Last CacheFile Failed.", ex);
+ }
+ }
+ var converter = control.Resources["treeNumber"] as RowNumberConverter;
+ converter.Reset();
+ var temp = LoadSteps(CurrentSeqUI.sequence);
+ SetIndex(temp);
+ AllSteps = temp;
+ }
+
+ void SetIndex(IEnumerable<StepUI> datas)
+ {
+ foreach (var data in datas)
+ {
+ if (indexType.Contains(data.Type))
+ {
+ data.CustomIndex = ++indexCache;
+ }
+ if (data.Children != null && data.Children.Count > 0)
+ {
+ SetIndex(data.Children);
+ }
+ }
+ }
+
+ partial void OnAllStepsChanged(ObservableCollection<StepUI> data)
+ {
+ TreeCollection = new TreeItemDataCollection(AllSteps, "Children", true);
+ }
+
+ partial void OnTreeItemDataChanged(TreeItemData data)
+ {
+ CurrentStepUI = data?.Data as StepUI;
+ }
+
+ partial void OnTargetTypeChanged(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ edits = new HashSet<string>
+ {
+ //StepTypeStr.PassFailTest,
+ //StepTypeStr.NumericLimitTest,
+ //StepTypeStr.NI_MultipleNumericLimitTest,
+ //StepTypeStr.StringValueTest,
+ //StepTypeStr.Action,
+ //StepTypeStr.NI_Wait,
+ //StepTypeStr.SequenceCall,
+ };
+ }
+ else
+ {
+ edits = new HashSet<string>(value.Split(MultiComboBox.splits, StringSplitOptions.RemoveEmptyEntries))
+ {
+ StepTypeStr.SequenceCall
+ };
+ }
+ }
+
+ partial void OnCurrentFilePathChanged(string value)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ CurrentFileName = string.Empty;
+ }
+ else
+ {
+ CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(value)}";
+ }
+ }
+
+ partial void OnCurrentStepUIChanged(StepUI stepUI)
+ {
+ var panel = StepUI2EPO.Convert2EditPanel(stepUI);
+ control.editPanelContainer.Child = panel;
+ if (stepUI != null)
+ {
+ //window.commonP.RefreshStep(stepUI);
+ }
+ }
+
+ partial void OnCurrentSeqUIChanged(SeqUI seqUI)
+ {
+ if (seqUI != null)
+ {
+ CurrentStepUI = null;
+ RefreshData();
+ }
+ CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}";
+ }
+ }
+}
--
Gitblit v1.9.1