diff --git a/BOB/Converters/InverseBooleanConverter.cs b/BOB/Converters/InverseBooleanConverter.cs new file mode 100644 index 0000000..a19c9a1 --- /dev/null +++ b/BOB/Converters/InverseBooleanConverter.cs @@ -0,0 +1,22 @@ +using System; +using System.Globalization; +using System.Windows.Data; + +namespace BOB.Converters +{ + public class InverseBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // null 视为 false,再取反 → true + var b = value as bool?; + return !(b ?? false); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + var b = value as bool?; + return !(b ?? false); + } + } +} diff --git a/BOB/Converters/ParameterToGotoSettingStringConverter.cs b/BOB/Converters/ParameterToGotoSettingStringConverter.cs deleted file mode 100644 index 531c03d..0000000 --- a/BOB/Converters/ParameterToGotoSettingStringConverter.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; - -namespace BOB.Converters -{ - public class ParameterToGotoSettingStringConverter : IValueConverter - { - private GlobalVariables _globalVariables; - public ParameterToGotoSettingStringConverter(GlobalVariables globalVariables) - { - _globalVariables= globalVariables; - } - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is Guid stepID && stepID == _globalVariables.SelectedStep!.ID) - { - if (_globalVariables.SelectedStep == null) - { - return ""; - } - if (_globalVariables.SelectedStep!.OKGotoStepID == null && _globalVariables.SelectedStep!.NGGotoStepID == null) - { - return "0/0"; - } - else - { - string gotoString = ""; - if (_globalVariables.SelectedStep!.OKGotoStepID != null) - { - var OKGotoStep = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.ID == _globalVariables.SelectedStep!.OKGotoStepID); - if (OKGotoStep != null) - { - gotoString = OKGotoStep.Index.ToString() + "/"; - } - else - { - gotoString = "0/"; - } - } - else - { - gotoString = "0/"; - } - if (_globalVariables.SelectedStep!.NGGotoStepID != null) - { - var NGGotoStep = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.ID == _globalVariables.SelectedStep!.NGGotoStepID); - if (NGGotoStep != null) - { - gotoString += NGGotoStep.Index.ToString(); - } - else - { - gotoString += "0"; - } - } - else - { - gotoString += "0"; - } - return gotoString; - } - } - return null; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is string gotoSettingstring) - { - gotoSettingstring = gotoSettingstring.Replace(" ", "").Replace("/n", "").Replace("/r", ""); - if (gotoSettingstring == "0/0") - { - _globalVariables.SelectedStep!.OKGotoStepID = null; - _globalVariables.SelectedStep!.NGGotoStepID = null; - } - else - { - try - { - var list = gotoSettingstring.Split("/"); - var okindex = System.Convert.ToInt32(list[0]); - var ngindex = System.Convert.ToInt32(list[1]); - if (okindex == 0) - { - _globalVariables.SelectedStep!.OKGotoStepID = null; - } - else - { - if (okindex > _globalVariables.Program.StepCollection.Count) - { - throw new Exception("步骤序号超出最大值"); - } - _globalVariables.SelectedStep!.OKGotoStepID = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.Index == okindex)?.ID; - } - if (ngindex == 0) - { - _globalVariables.SelectedStep!.NGGotoStepID = null; - } - else - { - if (ngindex > _globalVariables.Program.StepCollection.Count) - { - throw new Exception("步骤序号超出最大值"); - } - _globalVariables.SelectedStep!.NGGotoStepID = _globalVariables.Program.StepCollection.FirstOrDefault(x => x.Index == ngindex)?.ID; - } - } - catch (Exception ex) - { - MessageBox.Show($"跳转表达式错误:{ex.Message}"); - } - } - } - return _globalVariables.SelectedStep!.ID; - } - } -} diff --git a/BOB/GlobalVariables.cs b/BOB/Singleton/GlobalVariables.cs similarity index 100% rename from BOB/GlobalVariables.cs rename to BOB/Singleton/GlobalVariables.cs diff --git a/BOB/StepRunning.cs b/BOB/Singleton/StepRunning.cs similarity index 96% rename from BOB/StepRunning.cs rename to BOB/Singleton/StepRunning.cs index aae0b65..8d26abd 100644 --- a/BOB/StepRunning.cs +++ b/BOB/Singleton/StepRunning.cs @@ -1,4 +1,5 @@ using BOB.Models; +using Common.PubEvent; using Common.Tools; using Logger; using MaterialDesignThemes.Wpf; @@ -18,6 +19,7 @@ namespace BOB public class StepRunning { private GlobalVariables _globalVariables; + private IEventAggregator _eventAggregator; private readonly Dictionary tmpParameters = []; @@ -31,9 +33,10 @@ namespace BOB private bool SubSingleStep = false; private Guid TestRoundID; - public StepRunning(GlobalVariables globalVariables) + public StepRunning(GlobalVariables globalVariables,IEventAggregator eventAggregator) { _globalVariables = globalVariables; + _eventAggregator= eventAggregator; } public async Task ExecuteSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default) { @@ -108,7 +111,7 @@ namespace BOB { if (loopStack.Count == 0) { - LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth); + LoggerHelper.ErrorWithNotify("未匹配的循环结束指令", depth:depth); step.Result = 2; index++; continue; @@ -203,7 +206,8 @@ namespace BOB { _globalVariables.IsStop = true; _globalVariables.RunState = "运行"; - _globalVariables.RunIcon = PackIconKind.Play; + _globalVariables.SingleStep = false; + _eventAggregator.GetEvent().Publish("Play"); } } } @@ -215,6 +219,7 @@ namespace BOB { try { + if(_globalVariables.Program.StepCollection.Count>1) _globalVariables.SelectedStep = null; await Task.Delay(SystemConfig.Instance.PerformanceLevel); @@ -227,7 +232,7 @@ namespace BOB } if (targetType == null) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth); + LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth: depth); step.Result = 2; } @@ -318,7 +323,7 @@ namespace BOB } catch (Exception ex) { - LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth); + LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth: depth); } } } @@ -342,7 +347,7 @@ namespace BOB if (method == null) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth); + LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth: depth); step.Result = 2; } @@ -350,7 +355,7 @@ namespace BOB bool isStaticMethod = method!.IsStatic; // 如果是实例方法,需要创建实例 - if (!isMethod) + if (!isStaticMethod) { try { @@ -358,7 +363,7 @@ namespace BOB } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth); + LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth: depth); step.Result = 2; } } @@ -396,7 +401,7 @@ namespace BOB } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth); + LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); step.Result = 2; return; } @@ -448,7 +453,7 @@ namespace BOB } catch (Exception ex) { - LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth); + LoggerHelper.ErrorWithNotify($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth: depth); step.Result = 2; return; } @@ -496,7 +501,7 @@ namespace BOB step.Result = re ? 1 : 2; if (step.Result == 2) { - LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth); + LoggerHelper.WarnWithNotify($"指令 [ {step.Index} ] NG:条件表达式验证失败", depth: depth); } } } @@ -504,7 +509,7 @@ namespace BOB { if (!paraResult) { - LoggerHelper.WarnWithNotify("参数限值校验失败", depth); + LoggerHelper.WarnWithNotify("参数限值校验失败", depth: depth); } step.Result = 2; } diff --git a/BOB/ViewModels/CommandTreeViewModel.cs b/BOB/ViewModels/CommandTreeViewModel.cs index 2505f17..0595b38 100644 --- a/BOB/ViewModels/CommandTreeViewModel.cs +++ b/BOB/ViewModels/CommandTreeViewModel.cs @@ -129,6 +129,10 @@ namespace BOB.ViewModels break; } } + else if(Node.Tag is SubProgramItem subProgram) + { + AddSubProgramToProgram(subProgram, index); + } } } } @@ -195,7 +199,7 @@ namespace BOB.ViewModels return; } - foreach (var filePath in Directory.GetFiles(SystemConfig.Instance.SubProgramFilePath, "*.ats")) + foreach (var filePath in Directory.GetFiles(SystemConfig.Instance.SubProgramFilePath, "*.bob")) { try { @@ -470,45 +474,42 @@ namespace BOB.ViewModels } } - //private void AddSubProgramToProgram(SubProgramItem subProgram, int insertIndex = -1) - //{ - // try - // { - // var newStep = new StepModel - // { - // Name = subProgram.Name, - // StepType = "子程序" - // }; - // var jsonstr = File.ReadAllText($"{subProgram.FilePath}"); - // var tmp = JsonConvert.DeserializeObject(jsonstr); - // if (tmp != null) - // { - // if (tmp.Devices != null && tmp.Devices.Count > 0) - // { - // foreach (var device in tmp.Devices) - // { - // _ = DeviceConnect.InitAndConnectDevice(tmp, device); - // } - // } - // newStep.SubProgram = tmp; - // } - // 添加到程序 - // if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count) - // { - // Program.StepCollection.Insert(insertIndex, newStep); - // } - // else - // { - // Program.StepCollection.Add(newStep); - // } - - // ReOrderProgramList(); - // } - // catch (Exception ex) - // { - // Log.Error($"添加子程序失败: {subProgram.Name} - {ex.Message}"); - // } - //} + private void AddSubProgramToProgram(SubProgramItem subProgram, int insertIndex = -1) + { + try + { + var newStep = new StepModel + { + Name = subProgram.Name, + StepType = "子程序" + }; + var jsonstr = File.ReadAllText($"{subProgram.FilePath}"); + var tmp = JsonConvert.DeserializeObject(jsonstr); + if (tmp != null) + { + if (tmp.Devices != null && tmp.Devices.Count > 0) + { + foreach (var device in tmp.Devices) + { + // _ = DeviceConnect.InitAndConnectDevice(tmp, device); + } + } + newStep.SubProgram = tmp; + } + if (insertIndex >= 0 && insertIndex <= Program.StepCollection.Count) + { + Program.StepCollection.Insert(insertIndex, newStep); + } + else + { + Program.StepCollection.Add(newStep); + } + } + catch (Exception ex) + { + LoggerHelper.ErrorWithNotify($"添加子程序失败: {subProgram.Name} - {ex.Message}"); + } + } private void AddLoopStartStep(int insertIndex = -1) { diff --git a/BOB/ViewModels/Dialogs/DeviceSettingViewModel.cs b/BOB/ViewModels/Dialogs/DeviceSettingViewModel.cs index 4358ab2..7f34b87 100644 --- a/BOB/ViewModels/Dialogs/DeviceSettingViewModel.cs +++ b/BOB/ViewModels/Dialogs/DeviceSettingViewModel.cs @@ -1,4 +1,5 @@ using BOB.Models; +using Common.PubEvent; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -62,11 +63,13 @@ namespace BOB.ViewModels.Dialogs #endregion public DialogCloseListener RequestClose { get; set; } private GlobalVariables _globalVariables; + private IEventAggregator _eventAggregator; public ICommand CancelCommand { get; set; } public ICommand SaveCommand { get; set; } public ICommand SelectionChangedCommand { get; set; } - public DeviceSettingViewModel(GlobalVariables globalVariables) + public DeviceSettingViewModel(GlobalVariables globalVariables, IEventAggregator eventAggregator) { + _eventAggregator = eventAggregator; _globalVariables = globalVariables; CancelCommand = new DelegateCommand(Cancel); SaveCommand = new DelegateCommand(Save); @@ -183,11 +186,12 @@ namespace BOB.ViewModels.Dialogs public void OnDialogClosed() { - + _eventAggregator.GetEvent().Publish(false); } public void OnDialogOpened(IDialogParameters parameters) { + _eventAggregator.GetEvent().Publish(true); Program = _globalVariables.Program; Mode = parameters.GetValue("Mode"); if(Mode == "ADD") diff --git a/BOB/ViewModels/Dialogs/MessageBoxViewModel.cs b/BOB/ViewModels/Dialogs/MessageBoxViewModel.cs index ffd8480..a74f352 100644 --- a/BOB/ViewModels/Dialogs/MessageBoxViewModel.cs +++ b/BOB/ViewModels/Dialogs/MessageBoxViewModel.cs @@ -100,6 +100,7 @@ namespace BOB.ViewModels.Dialogs public void OnDialogOpened(IDialogParameters parameters) { + _eventAggregator.GetEvent().Publish(true); Title = parameters.GetValue("Title"); Message = parameters.GetValue("Message"); var iconKey = parameters.GetValue("Icon"); // info / error / warn diff --git a/BOB/ViewModels/Dialogs/ParameterSettingViewModel.cs b/BOB/ViewModels/Dialogs/ParameterSettingViewModel.cs index 93dec73..edfa51d 100644 --- a/BOB/ViewModels/Dialogs/ParameterSettingViewModel.cs +++ b/BOB/ViewModels/Dialogs/ParameterSettingViewModel.cs @@ -1,4 +1,5 @@ using BOB.Models; +using Common.PubEvent; using SqlSugar; using System; using System.Collections.Generic; @@ -69,10 +70,12 @@ namespace BOB.ViewModels.Dialogs #endregion public DialogCloseListener RequestClose{get;set;} private GlobalVariables _globalVariables; + private IEventAggregator _eventAggregator; public ICommand CancelCommand { get; set; } public ICommand SaveCommand { get; set; } - public ParameterSettingViewModel(GlobalVariables globalVariables) + public ParameterSettingViewModel(GlobalVariables globalVariables, IEventAggregator eventAggregator) { + _eventAggregator = eventAggregator; _globalVariables = globalVariables; CancelCommand = new DelegateCommand(Cancel); SaveCommand = new DelegateCommand(Save); @@ -112,12 +115,13 @@ namespace BOB.ViewModels.Dialogs public void OnDialogClosed() { - + _eventAggregator.GetEvent().Publish(false); } public void OnDialogOpened(IDialogParameters parameters) { - Program=_globalVariables.Program; + _eventAggregator.GetEvent().Publish(true); + Program =_globalVariables.Program; Mode = parameters.GetValue("Mode"); if (Mode == "ADD") { diff --git a/BOB/ViewModels/LogAreaViewModel.cs b/BOB/ViewModels/LogAreaViewModel.cs index 015171c..835d258 100644 --- a/BOB/ViewModels/LogAreaViewModel.cs +++ b/BOB/ViewModels/LogAreaViewModel.cs @@ -2,6 +2,7 @@ using Prism.Mvvm; using System.Collections.ObjectModel; using System.Windows; +using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; @@ -16,18 +17,21 @@ namespace BOB.ViewModels get => _logs; set => SetProperty(ref _logs, value); } - + public ICommand ClearLogCommand { get; set; } public LogAreaViewModel() { - LoggerHelper.LogAdded += OnLogAdded; + ClearLogCommand = new DelegateCommand(ClearLog); + LoggerHelper.Progress = new System.Progress<(string message, string color,int depth)>( + log => + { + var brush = (Brush)new BrushConverter().ConvertFromString(log.color); + Logs.Add(new LogItem(log.message, brush, log.depth)); + }); } - // 方便外部添加日志 - public void OnLogAdded(string message, string color) + private void ClearLog() { - var brush = (Brush)new BrushConverter().ConvertFromString(color); - Application.Current.Dispatcher.Invoke(() => Logs.Add(new LogItem { Message = message, Color = brush })); - + Logs.Clear(); } } @@ -36,5 +40,12 @@ namespace BOB.ViewModels { public string Message { get; set; } public Brush Color { get; set; } = Brushes.Black; + public int Depth { get; set; } + public LogItem(string message, Brush color, int depth = 0) + { + Message = new string(' ', depth * 20) + message; + Color = color; + Depth = depth; + } } } diff --git a/BOB/ViewModels/ParametersManagerViewModel.cs b/BOB/ViewModels/ParametersManagerViewModel.cs index 3f3b93e..6987cc7 100644 --- a/BOB/ViewModels/ParametersManagerViewModel.cs +++ b/BOB/ViewModels/ParametersManagerViewModel.cs @@ -97,13 +97,12 @@ namespace BOB.ViewModels { if (r.Result == ButtonResult.OK) { - + _eventAggregator.GetEvent().Publish(); } else { } - _eventAggregator.GetEvent().Publish(false); }); } @@ -114,18 +113,16 @@ namespace BOB.ViewModels { { "Mode", "ADD" } }; - _eventAggregator.GetEvent().Publish(true); _dialogService.ShowDialog("DeviceSetting", param, (r) => { if (r.Result == ButtonResult.OK) { - + _eventAggregator.GetEvent().Publish(); } else { } - _eventAggregator.GetEvent().Publish(false); }); } @@ -144,13 +141,13 @@ namespace BOB.ViewModels { if (r.Result == ButtonResult.OK) { - + _eventAggregator.GetEvent().Publish(); } else { } - _eventAggregator.GetEvent().Publish(false); + }); } @@ -164,13 +161,13 @@ namespace BOB.ViewModels { if (r.Result == ButtonResult.OK) { - + _eventAggregator.GetEvent().Publish(); } else { } - _eventAggregator.GetEvent().Publish(false); + }); } #endregion diff --git a/BOB/ViewModels/ShellViewModel.cs b/BOB/ViewModels/ShellViewModel.cs index 8920691..eb8fa14 100644 --- a/BOB/ViewModels/ShellViewModel.cs +++ b/BOB/ViewModels/ShellViewModel.cs @@ -1,5 +1,6 @@ using BOB.Models; using BOB.Views; +using Common.PubEvent; using Common.PubEvents; using Logger; using MaterialDesignThemes.Wpf; @@ -28,6 +29,13 @@ namespace BOB.ViewModels get => _IsLeftDrawerOpen; set => SetProperty(ref _IsLeftDrawerOpen, value); } + private bool _IsTerminate=false; + + public bool IsTerminate + { + get => _IsTerminate; + set => SetProperty(ref _IsTerminate, value); + } public String RunState { @@ -109,6 +117,17 @@ namespace BOB.ViewModels SaveCommand = new DelegateCommand(Save); SetDefaultCommand = new DelegateCommand(SetDefault); LoadCommand = new DelegateCommand(Load); + _eventAggregator.GetEvent().Subscribe(UpdateRunIcon); + } + + private void UpdateRunIcon(string obj) + { + RunIcon= obj switch + { + "Play" => PackIconKind.Play, + "Pause" => PackIconKind.Pause, + _ => RunIcon + }; } #region ToolBar命令 private void Load() @@ -206,11 +225,10 @@ namespace BOB.ViewModels { _globalVariables.CurrentFilePath = saveFileDialog.FileName; SaveProgramToFile(_globalVariables.CurrentFilePath); + // 记录日志 + LoggerHelper.InfoWithNotify($"{_globalVariables.UserName} 另存为文件成功: {saveFileDialog.FileName}"); } - // 记录日志 - LoggerHelper.InfoWithNotify($"{_globalVariables.UserName} 另存为文件成功: {saveFileDialog.FileName}"); - } private void SaveProgramToFile(string filePath) { @@ -251,16 +269,29 @@ namespace BOB.ViewModels return; } SaveProgramToFile(_globalVariables.CurrentFilePath); - LoggerHelper.InfoWithNotify(_globalVariables.UserName + "保存文件成功"); + } private void Stop() { - LoggerHelper.InfoWithNotify(_globalVariables.UserName+"执行停止命令"); + if (_globalVariables.IsStop == false) + { + LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行停止命令"); + IsTerminate = true; + _globalVariables.IsStop = null; + RunState = "运行"; + RunIcon = PackIconKind.Play; + _stepRunning.stepCTS.Cancel(); + } } private void Resotration() { LoggerHelper.InfoWithNotify(_globalVariables.UserName + "执行复位命令"); + IsTerminate = false; + currentExecutionTask = null; + _stepRunning.stepCTS = new(); + _globalVariables.IsStop = null; + _stepRunning.ResetAllStepStatus(_globalVariables.Program); } private async void RunSingle() @@ -274,11 +305,12 @@ namespace BOB.ViewModels if (_globalVariables.IsStop == null) { _globalVariables.IsStop = false; - currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token); + if(currentExecutionTask==null)currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token); await currentExecutionTask; RunState = "运行"; RunIcon = PackIconKind.Play; _globalVariables.IsStop = null; + IsTerminate = true; } else if (_globalVariables.IsStop == true) { @@ -299,11 +331,12 @@ namespace BOB.ViewModels if (_globalVariables.IsStop == null) { _globalVariables.IsStop = false; - currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token); + if (currentExecutionTask == null) currentExecutionTask = _stepRunning.ExecuteSteps(_globalVariables.Program, cancellationToken: _stepRunning.stepCTS.Token); await currentExecutionTask; RunState = "运行"; RunIcon = PackIconKind.Play; _globalVariables.IsStop = null; + IsTerminate = true; } else if (_globalVariables.IsStop == true) { diff --git a/BOB/ViewModels/SingleStepEditViewModel.cs b/BOB/ViewModels/SingleStepEditViewModel.cs index fd2b4ec..f2b6678 100644 --- a/BOB/ViewModels/SingleStepEditViewModel.cs +++ b/BOB/ViewModels/SingleStepEditViewModel.cs @@ -1,10 +1,15 @@ using BOB.Models; using Common.PubEvent; +using Logger; +using Microsoft.IdentityModel.Logging; +using SqlSugar.Extensions; using System; using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; +using System.Windows; using System.Windows.Input; namespace BOB.ViewModels @@ -39,16 +44,24 @@ namespace BOB.ViewModels #endregion private GlobalVariables _globalVariables; private IEventAggregator _eventAggregator; + private IDialogService _dialogService; public ICommand CancelEditCommand { get; set; } public ICommand SaveStepCommand { get; set; } - public SingleStepEditViewModel(GlobalVariables globalVariables,IEventAggregator eventAggregator) + public SingleStepEditViewModel(GlobalVariables globalVariables,IEventAggregator eventAggregator,IDialogService dialogService) { _globalVariables= globalVariables; _eventAggregator= eventAggregator; + _dialogService = dialogService; _eventAggregator.GetEvent().Subscribe(EditSingleSetp); CancelEditCommand = new DelegateCommand(CancelEdit); SaveStepCommand = new DelegateCommand(SaveStep); _eventAggregator.GetEvent().Subscribe(DisposeSelectedStep); + _eventAggregator.GetEvent().Subscribe(ParamsChanged); + } + + private void ParamsChanged() + { + CancelEdit(); } private void DisposeSelectedStep(Guid id) @@ -74,10 +87,105 @@ namespace BOB.ViewModels if (index >= 0) { steps[index] = SelectedStep; + if (steps[index].Method != null) + { + if (steps[index].StepType == "循环开始") + { + try + { + steps[index].LoopCount = Convert.ToInt32(SelectedStep.Method!.Parameters[0].Value); + } + catch + { + LoggerHelper.ErrorWithNotify("循环指令参数设置错误:类型转换失败"); + } + } + else + { + (steps[index].OKGotoStepID, steps[index].NGGotoStepID) = GetOKNGGotoStepID(SelectedStep.GotoSettingString); + for (int i = 0; i < steps[index].Method.Parameters.Count; i++) + { + var editedParam = SelectedStep.Method!.Parameters[i]; + var originalParam = steps[index].Method.Parameters[i]; + if (editedParam.IsUseVar) + { + originalParam.VariableName = editedParam.VariableName; + originalParam.VariableID = _globalVariables.Program.Parameters.FirstOrDefault(x => x.Name == editedParam.VariableName)!.ID; + } + originalParam.Value = editedParam.Value; + originalParam.IsUseVar = editedParam.IsUseVar; + originalParam.LowerLimit = editedParam.LowerLimit; + originalParam.UpperLimit = editedParam.UpperLimit; + } + var parameters = new DialogParameters + { + { "Title", "提示" }, + { "Message", "保存成功!" }, + { "Icon", "info" }, + { "ShowOk", true } + }; + _dialogService.ShowDialog("MessageBox", parameters); + } + } + else if (steps[index].SubProgram != null) + { + if (SelectedStep.SubProgram.Parameters.Where(x => x.VariableName == null && x.IsUseVar == true).FirstOrDefault() != null) + { + var parameters1 = new DialogParameters + { + { "Title", "警告" }, + { "Message", "选中变量不得为空!" }, + { "Icon", "warn" }, + { "ShowOk", true }, + }; + _dialogService.ShowDialog("MessageBox",parameters1); + return; + } + (steps[index].OKGotoStepID, steps[index].NGGotoStepID) = GetOKNGGotoStepID(SelectedStep.GotoSettingString); + for (int i = 0; i < steps[index].SubProgram.Parameters.Count; i++) + { + var editedParam = SelectedStep.SubProgram!.Parameters[i]; + var originalParam = steps[index].SubProgram.Parameters[i]; + if (editedParam.IsUseVar) + { + originalParam.VariableName = editedParam.VariableName; + originalParam.VariableID = _globalVariables.Program.Parameters.FirstOrDefault(x => x.Name == editedParam.VariableName)!.ID; + } + originalParam.Value = editedParam.Value; + originalParam.IsUseVar = editedParam.IsUseVar; + originalParam.LowerLimit = editedParam.LowerLimit; + originalParam.UpperLimit = editedParam.UpperLimit; + } + var parameters = new DialogParameters + { + { "Title", "提示" }, + { "Message", "保存成功!" }, + { "Icon", "info" }, + { "ShowOk", true } + }; + _dialogService.ShowDialog("MessageBox", parameters); + } } } + private (Guid,Guid) GetOKNGGotoStepID(string GotoSettingString) + { + if (string.IsNullOrWhiteSpace(GotoSettingString)) + return (Guid.Empty, Guid.Empty); + var match = Regex.Match(GotoSettingString, @"^(\d+)\s*/\s*(\d+)$"); + if (match.Success) + { + int ok = int.Parse(match.Groups[1].Value); + int ng = int.Parse(match.Groups[2].Value); + + Guid okGuid = _globalVariables.Program.StepCollection.ElementAtOrDefault(ok-1)?.ID ?? Guid.Empty; + Guid ngGuid = _globalVariables.Program.StepCollection.ElementAtOrDefault(ng-1)?.ID ?? Guid.Empty; + + return (okGuid, ngGuid); + } + return (Guid.Empty, Guid.Empty); + } private void EditSingleSetp() { ID = _globalVariables.SelectedStep.ID; diff --git a/BOB/Views/LogArea.xaml b/BOB/Views/LogArea.xaml index 467fc92..75b9b41 100644 --- a/BOB/Views/LogArea.xaml +++ b/BOB/Views/LogArea.xaml @@ -11,10 +11,16 @@ - - + + + + + - /// LogArea.xaml 的交互逻辑 - /// public partial class LogArea : UserControl { public LogArea() { InitializeComponent(); + + // 绑定 DataContext 后,订阅日志集合变化 + this.Loaded += (s, e) => + { + if (DataContext is LogAreaViewModel vm) + { + vm.Logs.CollectionChanged += Logs_CollectionChanged; + } + }; + } + + private void Logs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + // 每次新增日志,滚动到最后一条 + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) + { + if (this.LogListView.Items.Count > 0) + { + this.LogListView.ScrollIntoView(this.LogListView.Items[^1]); + } + } } } } diff --git a/BOB/Views/ShellView.xaml b/BOB/Views/ShellView.xaml index 7683515..37d9d5d 100644 --- a/BOB/Views/ShellView.xaml +++ b/BOB/Views/ShellView.xaml @@ -7,7 +7,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:i="http://schemas.microsoft.com/xaml/behaviors" WindowStartupLocation="CenterScreen" - Topmost="false" + xmlns:converter="clr-namespace:BOB.Converters" mc:Ignorable="d" prism:ViewModelLocator.AutoWireViewModel="True" WindowStyle="None" @@ -23,7 +23,9 @@ - + + + @@ -146,6 +148,7 @@ @@ -156,6 +159,7 @@ @@ -176,6 +180,7 @@ @@ -241,15 +246,15 @@ - + + + Grid.ColumnSpan="4" /> diff --git a/BOB/Views/SingleStepEdit.xaml b/BOB/Views/SingleStepEdit.xaml index ab489d8..597fe09 100644 --- a/BOB/Views/SingleStepEdit.xaml +++ b/BOB/Views/SingleStepEdit.xaml @@ -325,7 +325,7 @@ Margin="0,0,0,0" materialDesign:HintAssist.Hint="" VerticalAlignment="Bottom" - ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Program.Parameters}" + ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=DataContext.Program.Parameters}" SelectedValue="{Binding VariableName}" SelectedValuePath="Name" Visibility="{Binding Category, Converter={StaticResource ParameterCategoryToVisibilityConverter}, ConverterParameter=Inverse}"> diff --git a/Common/PubEvent/ParamsChangedEvent.cs b/Common/PubEvent/ParamsChangedEvent.cs new file mode 100644 index 0000000..cbcc77e --- /dev/null +++ b/Common/PubEvent/ParamsChangedEvent.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Common.PubEvent +{ + public class ParamsChangedEvent:PubSubEvent + { + } +} diff --git a/Common/PubEvent/UpdateIconEvent.cs b/Common/PubEvent/UpdateIconEvent.cs new file mode 100644 index 0000000..e5e6071 --- /dev/null +++ b/Common/PubEvent/UpdateIconEvent.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Common.PubEvent +{ + public class UpdateIconEvent: PubSubEvent + { + } +} diff --git a/Logger/LoggerHelper.cs b/Logger/LoggerHelper.cs index 1d20811..33e7ee0 100644 --- a/Logger/LoggerHelper.cs +++ b/Logger/LoggerHelper.cs @@ -13,22 +13,23 @@ namespace Logger { public static readonly ILogger Logger = LogManager.GetLogger("InfoLogger"); public static readonly ILogger sqlLogger = LogManager.GetLogger("SqlLogger"); - // 日志事件,UI可以订阅 - - public static event Action? LogAdded; - - public static void InfoWithNotify(string message) + public static IProgress<(string message, string color,int depth)> Progress { get; set; } + static LoggerHelper() + { + Progress = new Progress<(string message, string color, int depth)>(); + } + public static void InfoWithNotify(string message, int depth=0) { Logger.Info(message); // 写入 NLog - NotifyUI(message, "lightblue"); // 触发UI显示 + NotifyUI(message, "blue", depth); // 触发UI显示 } - public static void SuccessWithNotify(string message) + public static void SuccessWithNotify(string message, int depth=0) { Logger.Info(message); - NotifyUI(message, "lightgreen"); + NotifyUI(message, "lightgreen", depth); } - public static void WarnWithNotify(string message, string stackTrace = null) + public static void WarnWithNotify(string message, string stackTrace = null, int depth = 0) { if (!string.IsNullOrEmpty(stackTrace)) { @@ -37,10 +38,10 @@ namespace Logger } Logger.Warn(message); - NotifyUI(message, "orange"); + NotifyUI(message, "orange", depth); } - public static void ErrorWithNotify(string message, string stackTrace = null) + public static void ErrorWithNotify(string message, string stackTrace = null, int depth = 0) { if (!string.IsNullOrEmpty(stackTrace)) { @@ -49,37 +50,11 @@ namespace Logger } Logger.Error(message); - NotifyUI(message, "red"); + NotifyUI(message, "red", depth); } - public static void InfoWithNotify(string message,int depth) + private static void NotifyUI(string message, string color, int depth) { - Logger.Info(message); // 写入 NLog - NotifyUI(message, "lightblue"); // 触发UI显示 - } - - public static void SuccessWithNotify(string message, int depth ) - { - Logger.Info(message); - NotifyUI(message, "lightgreen"); - } - public static void WarnWithNotify(string message, int depth ) - { - - - Logger.Warn(message); - NotifyUI(message, "orange"); - } - - public static void ErrorWithNotify(string message, int depth ) - { - - - Logger.Error(message); - NotifyUI(message, "red"); - } - private static void NotifyUI(string message, string color) - { - LogAdded?.Invoke(message,color); + Progress.Report((message, color, depth)); } // 解析堆栈,找到项目文件路径和行号 public static string GetProjectStackLine(string stackTrace)