From 771a0e7b6b1276087515bbe94de28358cb92963b Mon Sep 17 00:00:00 2001
From: alielie <alielie@git.com>
Date: 星期四, 04 六月 2026 10:32:27 +0800
Subject: [PATCH] 优化老化;

---
 Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs |  463 +++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 362 insertions(+), 101 deletions(-)

diff --git a/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
index b369169..fe22156 100644
--- a/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
+++ b/Plugin.SeqEditor/ViewModel/SeqEditorViewModel.cs
@@ -1,5 +1,6 @@
 锘縰sing CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using GongSolutions.Wpf.DragDrop;
 using HMI.Core.Util;
 using HMI.UI;
 using HMI.UI.Util;
@@ -11,6 +12,12 @@
 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
 {
@@ -44,25 +51,36 @@
         [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> {
+        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.Action,
             StepTypeStr.NI_Wait,
-            StepTypeStr.SequenceCall,
-        };
+            StepTypeStr.Action
+    };
 
         public SeqEditorViewModel(SeqEditor control, ILog log)
         {
@@ -70,6 +88,8 @@
             this.control = control;
             engine = new Engine();
             engine.LoadTypePaletteFilesEx();
+            TargetType = string.Empty;
+            StepDropHandler = new TreeListViewHandler(this);
         }
 
         ~SeqEditorViewModel()
@@ -80,14 +100,23 @@
                 {
                     engine.ReleaseSequenceFileEx(sequenceFile);
                 }
+                foreach (var file in cacheFiles.Values)
+                {
+                    engine.ReleaseSequenceFileEx(file);
+                }
                 engine.ShutDown(true);
                 // 涓嶅姞寤舵椂浼氬脊绐梞d
-                System.Threading.Thread.Sleep(2500);
+                //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);
@@ -133,46 +162,53 @@
             //CurrentStepUI = null;
 
             var steps = new ObservableCollection<StepUI>();
+            StepGroups[] groups = new StepGroups[] { StepGroups.StepGroup_Setup, StepGroups.StepGroup_Main, StepGroups.StepGroup_Cleanup };
 
-            int num = seq.GetNumSteps(StepGroups.StepGroup_Setup);
-            for (int i = 0; i < num; i++)
+            foreach (var stepGroup in groups)
             {
-                Step step = seq.GetStep(i, StepGroups.StepGroup_Setup);
-                var ui = Convert2StepUI(step, group);
-                if (ui != null)
+                int num = seq.GetNumSteps(stepGroup);
+                for (int i = 0; i < num; i++)
                 {
-                    steps.Add(ui);
+                    Step step = seq.GetStep(i, stepGroup);
+                    var ui = Convert2StepUI(i, step, seq, group);
+                    if (ui != null)
+                    {
+                        steps.Add(ui);
+                    }
                 }
             }
 
-            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, 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, 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 StepUI Convert2StepUI(Step step, string group)
+        private int indexCache = 0;
+
+        private StepUI Convert2StepUI(int index, Step step, Sequence sequence, string group)
         {
-            var ui = new StepUI(step);
-            if (!edits.Contains(ui.Type))
+            var ui = new StepUI(step, sequence);
+            if (edits != null && edits.Count > 0 && !edits.Contains(ui.Type))
             {
                 return null;
             }
@@ -202,16 +238,54 @@
             {
                 var po = step.Module.AsPropertyObject();
                 bool useCurFile = po.GetValBoolean("UseCurFile", 0);
-                if (useCurFile)
+                string sfPath = po.GetValString("SFPath", 0);
+                if (useCurFile || Path.GetFileName(currentFilePath).Equals(sfPath, StringComparison.CurrentCultureIgnoreCase))
                 {
                     string seqName = po.GetValString("SeqName", 0);
-                    Sequence sequence = sequenceFile.GetSequenceByName(seqName);
-                    if (sequence == null)
+                    Sequence sunSequence = sequenceFile.GetSequenceByName(seqName);
+                    if (sunSequence == null)
                     {
                         return ui;
                     }
-                    ui.Children = LoadSteps(sequence, group);
+                    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;
         }
@@ -232,20 +306,19 @@
             {
                 Filter = $"{LangUtil.Get("se.seq")}|*.seq;"
             };
-            if (ofd.ShowDialog() == true)
+            if (ofd.ShowDialog() == true && DoClose())
             {
                 control.BackgroundAction(() =>
                 {
                     try
                     {
                         var start = DateTime.Now;
-                        currentFilePath = ofd.FileName;
-                        CurrentFileName = $"{LangUtil.Get("se.currentFile")}{Path.GetFileName(currentFilePath)}";
+                        CurrentFilePath = ofd.FileName;
                         if (sequenceFile != null)
                         {
                             engine.ReleaseSequenceFileEx(sequenceFile);
                         }
-                        sequenceFile = engine.GetSequenceFileEx(currentFilePath);
+                        sequenceFile = engine.GetSequenceFileEx(CurrentFilePath);
                         Sequence main = sequenceFile.GetSequenceByName("MainSequence");
                         CurrentSeqUI = new SeqUI(main);
 
@@ -257,15 +330,19 @@
                         //}
                         //Sequences = seqs;
 
-                        if (Sequences != null && Sequences.Count > 0)
-                        {
-                            CurrentSeqUI = Sequences[0];
-                        }
-                        log.Info($"Open File [{currentFilePath}] In {(DateTime.Now - start).TotalMilliseconds}ms");
+                        //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"));
             }
@@ -274,54 +351,105 @@
         [RelayCommand]
         private void SaveSeqFile()
         {
-            sequenceFile?.Save(currentFilePath);
+            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;
-            if (string.IsNullOrEmpty(TargetType))
-            {
-                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>(TargetType.Split(','))
-                {
-                    StepTypeStr.SequenceCall
-                };
-            }
-            AllSteps = LoadSteps(CurrentSeqUI.sequence);
+            RefreshData();
         }
 
-        [RelayCommand]
-        private void CloseSeqFile()
+        private bool DoClose()
         {
-            //AllSteps = new ObservableCollection<StepUI>();
+            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;
+            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]
@@ -330,21 +458,22 @@
             try
             {
                 var group = CurrentStepUI.step.StepGroup;
+                var targetSequence = CurrentStepUI.sequence;
 
-                ObservableCollection<StepUI> source;
-                if (group == StepGroups.StepGroup_Setup)
-                {
-                    source = setupSteps;
-                }
-                else if (group == StepGroups.StepGroup_Main)
-                {
-                    source = mainSteps;
-                }
-                else
-                {
-                    source = cleanupSteps;
-                }
-                int index = source.IndexOf(CurrentStepUI);
+                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;
@@ -355,14 +484,6 @@
                     case "Tests.PassFail":
                         newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.PassFailTest);
                         newStep.Name = DefaultStepName.PassFailTest;
-                        var p = newStep.AsPropertyObject();
-                        string name = p.Name;
-                        var ps = p.GetSubProperties("", 0);
-                        foreach (var pp in ps)
-                        {
-                            string sname = pp.Name;
-                        }
-
                         break;
                     case "Tests.NumericLimitTest":
                         newStep = engine.NewStep(AdapterKeyNames.FlexLVAdapterKeyName, StepTypeStr.NumericLimitTest);
@@ -408,12 +529,37 @@
                         newStep = engine.NewStep(AdapterKeyNames.PythonAdapterKeyName, StepTypeStr.Action);
                         newStep.Name = DefaultStepName.Action;
                         break;
-
                     default:
                         return;
                 }
-                CurrentSeqUI.sequence.InsertStep(newStep, index + 1, group);
-                AllSteps = LoadSteps(CurrentSeqUI.sequence);
+                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)
             {
@@ -422,12 +568,128 @@
             }
         }
 
+        [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)
@@ -436,7 +698,6 @@
             control.editPanelContainer.Child = panel;
             if (stepUI != null)
             {
-
                 //window.commonP.RefreshStep(stepUI);
             }
         }
@@ -446,7 +707,7 @@
             if (seqUI != null)
             {
                 CurrentStepUI = null;
-                AllSteps = LoadSteps(seqUI.sequence);
+                RefreshData();
             }
             CurrentSeqTitle = $"{seqUI?.Name} {LangUtil.Get("se.steps")}";
         }

--
Gitblit v1.9.1