using 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.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 setupSteps = new ObservableCollection(); private ObservableCollection mainSteps = new ObservableCollection(); private ObservableCollection cleanupSteps = new ObservableCollection(); [ObservableProperty] private ObservableCollection allSteps = new ObservableCollection(); [ObservableProperty] private ObservableCollection sequences = new ObservableCollection(); [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; private bool isLoaded; private ILog log; public SeqEditor control { get; private set; } public List Types = FilterTypeData.ItemSource; private HashSet edits = new HashSet(); public Dictionary> sequenceCache { get; private set; } = new(); 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); } engine.ShutDown(true); // 不加延时会弹窗md System.Threading.Thread.Sleep(2500); } } private ObservableCollection LoadSteps(Sequence seq, string group = null) { if (sequenceCache.ContainsKey(seq)) { return sequenceCache[seq]; } //setupSteps.Clear(); //var steps = new ObservableCollection(); //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(); //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(); //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(); 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 { ui.CustomIndex = ++indexCache; } 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(); //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; 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; 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); sequenceFile = null; } 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 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 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 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(); AllSteps = LoadSteps(CurrentSeqUI.sequence); } partial void OnAllStepsChanged(ObservableCollection 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 { //StepTypeStr.PassFailTest, //StepTypeStr.NumericLimitTest, //StepTypeStr.NI_MultipleNumericLimitTest, //StepTypeStr.StringValueTest, //StepTypeStr.Action, //StepTypeStr.NI_Wait, //StepTypeStr.SequenceCall, }; } else { edits = new HashSet(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")}"; } } }