diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/App.axaml.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/App.axaml.cs index 6fcaf5b..5a591f7 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/App.axaml.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/App.axaml.cs @@ -5,12 +5,17 @@ using Avalonia.Data.Core.Plugins; using Avalonia.Markup.Xaml; using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModels; using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Views; +using Serilog; +using System; using System.Linq; +using System.Threading.Tasks; namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance { public partial class App : Application { + private static bool exceptionHandlersRegistered; + public override void Initialize() { AvaloniaXamlLoader.Load(this); @@ -18,6 +23,8 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance public override void OnFrameworkInitializationCompleted() { + RegisterExceptionHandlers(); + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.MainWindow = new MainWindow @@ -28,5 +35,33 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance base.OnFrameworkInitializationCompleted(); } + + private static void RegisterExceptionHandlers() + { + if (exceptionHandlersRegistered) + { + return; + } + + AppDomain.CurrentDomain.UnhandledException += (_, args) => + { + if (args.ExceptionObject is Exception exception) + { + Log.Fatal(exception, "捕获到 AppDomain 未处理异常,IsTerminating={IsTerminating}", args.IsTerminating); + } + else + { + Log.Fatal("捕获到 AppDomain 未处理异常:{ExceptionObject}", args.ExceptionObject); + } + }; + + TaskScheduler.UnobservedTaskException += (_, args) => + { + Log.Error(args.Exception, "捕获到未观察的后台任务异常"); + args.SetObserved(); + }; + + exceptionHandlersRegistered = true; + } } -} \ No newline at end of file +} diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Footwear Test methodsfor wholeshoe Slipresistanceperformance.csproj b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Footwear Test methodsfor wholeshoe Slipresistanceperformance.csproj index 802a661..b79c0d4 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Footwear Test methodsfor wholeshoe Slipresistanceperformance.csproj +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Footwear Test methodsfor wholeshoe Slipresistanceperformance.csproj @@ -25,6 +25,8 @@ + + diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/AdcZeroCalibration.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/AdcZeroCalibration.cs new file mode 100644 index 0000000..71ed377 --- /dev/null +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/AdcZeroCalibration.cs @@ -0,0 +1,7 @@ +namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Models +{ + public sealed record AdcZeroCalibration( + int NormalPressureZero, + int FrictionZero1, + int FrictionZero2); +} diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/PlcDeviceParameters.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/PlcDeviceParameters.cs new file mode 100644 index 0000000..a19f3a8 --- /dev/null +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Models/PlcDeviceParameters.cs @@ -0,0 +1,7 @@ +namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Models +{ + public sealed record PlcDeviceParameters( + double ManualSpeed, + double ManualDisplacement, + double TestSpeed); +} diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Program.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Program.cs index aa9dd7f..104b674 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Program.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Program.cs @@ -1,18 +1,35 @@ -using Avalonia; +using Avalonia; +using Serilog; using System; +using System.IO; namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance { internal sealed class Program { - // Initialization code. Don't use any Avalonia, third-party APIs or any - // SynchronizationContext-reliant code before AppMain is called: things aren't initialized - // yet and stuff might break. [STAThread] - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); + public static int Main(string[] args) + { + ConfigureLogging(); + + try + { + Log.Information("鞋类整鞋防滑性能试验程序启动"); + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + return 0; + } + catch (Exception ex) + { + Log.Fatal(ex, "程序发生致命异常并退出"); + return 1; + } + finally + { + Log.Information("鞋类整鞋防滑性能试验程序退出"); + Log.CloseAndFlush(); + } + } - // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() @@ -21,5 +38,27 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance #endif .WithInterFont() .LogToTrace(); + + private static void ConfigureLogging() + { + var logDirectory = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "FootwearSlipResistance", + "Logs"); + Directory.CreateDirectory(logDirectory); + + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Debug() + .WriteTo.File( + Path.Combine(logDirectory, "app-.log"), + rollingInterval: RollingInterval.Day, + retainedFileCountLimit: 30, + fileSizeLimitBytes: 20 * 1024 * 1024, + rollOnFileSizeLimit: true, + shared: true, + flushToDiskInterval: TimeSpan.FromSeconds(1), + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}") + .CreateLogger(); + } } } diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipExcelExportService.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipExcelExportService.cs index c3793bc..c548523 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipExcelExportService.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipExcelExportService.cs @@ -2,6 +2,7 @@ using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Models; +using Serilog; using System; using System.Collections.Generic; using System.Globalization; @@ -28,6 +29,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services : report.TestNumber); var path = Path.Combine(directory, $"{safeNumber}_防滑性能测试报告.xlsx"); + Log.Information( + "开始导出防滑性能 Excel:TestNumber={TestNumber}, ResultCount={ResultCount}, PointCount={PointCount}, Path={Path}", + report.TestNumber, + report.Results.Count, + report.Points.Count, + path); + using var document = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook); var workbookPart = document.AddWorkbookPart(); workbookPart.Workbook = new Workbook(); @@ -38,6 +46,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services AddDataSheet(workbookPart, sheets, 3, report.Points); workbookPart.Workbook.Save(); + Log.Information("防滑性能 Excel 导出完成:Path={Path}", path); return path; } diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs index 3e0df88..5bc891f 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Services/SlipResistanceDeviceService.cs @@ -1,6 +1,7 @@ using Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Models; using NModbus; using NModbus.IO; +using Serilog; using System; using System.Globalization; using System.IO.Ports; @@ -37,10 +38,16 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services private IModbusSerialMaster? adcMaster; private DeviceSettings settings = new("0.00", "0.00", "0.30", "0", "0.00", "0", "0.00", "0", "0.00", "COM7", "COM8", 115200); private SlipDeviceSnapshot snapshot = SlipDeviceSnapshot.Offline(); + private DateTime lastAdcErrorLoggedAt = DateTime.MinValue; + private DateTime lastPlcErrorLoggedAt = DateTime.MinValue; private double verticalLoadN; private double horizontalFrictionN; private double displacementMm; + private int pressureRawValue; + private int frictionRawValue1; + private int frictionRawValue2; + private bool hasAdcRawValues; private bool isTestRunning; private bool isResetting; private bool isConnected; @@ -64,6 +71,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services try { + Log.Information( + "启动防滑测试设备连接:PLC={PlcPort}, ADC={AdcPort}, BaudRate={BaudRate}, SlaveId={SlaveId}", + settings.PlcPortName, + settings.AdcPortName, + settings.BaudRate, + SlaveId); + plcPort = CreatePort(settings.PlcPortName, settings.BaudRate); adcPort = CreatePort(settings.AdcPortName, settings.BaudRate); plcPort.Open(); @@ -79,9 +93,16 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services SetConnected(true, string.Empty); adcTask = Task.Run(() => PollAdc(token), token); plcTask = Task.Run(() => PollPlc(token), token); + Log.Information("防滑测试设备连接成功,ADC/PLC 轮询已启动"); } catch (Exception ex) { + Log.Error( + ex, + "防滑测试设备连接失败:PLC={PlcPort}, ADC={AdcPort}, BaudRate={BaudRate}", + settings.PlcPortName, + settings.AdcPortName, + settings.BaudRate); SetConnected(false, ex.Message); Stop(); } @@ -90,6 +111,14 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services public void UpdateSettings(DeviceSettings deviceSettings) { settings = deviceSettings; + Log.Debug( + "设备设置已更新:PLC={PlcPort}, ADC={AdcPort}, BaudRate={BaudRate}, TestSpeed={TestSpeed}, ManualSpeed={ManualSpeed}, ManualDisplacement={ManualDisplacement}", + settings.PlcPortName, + settings.AdcPortName, + settings.BaudRate, + settings.TestSpeed, + settings.ManualSpeed, + settings.ManualDisplacement); } public Task PulseStartTestAsync() => PulseCoilAsync(StartTestCoil); @@ -120,8 +149,50 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services public Task WriteManualDisplacementAsync(double value) => WriteFloatRegisterAsync(ManualDisplacementRegister, value); + public Task ReadDeviceParametersAsync() => + Task.Run(() => + { + var master = plcMaster ?? throw new InvalidOperationException("PLC 未连接"); + var manualSpeedWords = master.ReadHoldingRegisters(SlaveId, ManualSpeedRegister, 2); + var manualDisplacementWords = master.ReadHoldingRegisters(SlaveId, ManualDisplacementRegister, 2); + var testSpeedWords = master.ReadHoldingRegisters(SlaveId, TestSpeedRegister, 2); + var parameters = new PlcDeviceParameters( + UshortToFloat(manualSpeedWords[1], manualSpeedWords[0]), + UshortToFloat(manualDisplacementWords[1], manualDisplacementWords[0]), + UshortToFloat(testSpeedWords[1], testSpeedWords[0])); + + Log.Information( + "读取 PLC 参数完成:D{ManualSpeedRegister}={ManualSpeed:F3}, D{ManualDisplacementRegister}={ManualDisplacement:F3}, D{TestSpeedRegister}={TestSpeed:F3}", + ManualSpeedRegister, + parameters.ManualSpeed, + ManualDisplacementRegister, + parameters.ManualDisplacement, + TestSpeedRegister, + parameters.TestSpeed); + return parameters; + }); + + public AdcZeroCalibration CaptureCurrentAdcZero() + { + lock (sync) + { + if (!hasAdcRawValues) + { + throw new InvalidOperationException("ADC 尚未读取到有效原始数据"); + } + + Log.Information( + "采集 ADC 零点:NormalPressureZero={NormalPressureZero}, FrictionZero1={FrictionZero1}, FrictionZero2={FrictionZero2}", + pressureRawValue, + frictionRawValue1, + frictionRawValue2); + return new AdcZeroCalibration(pressureRawValue, frictionRawValue1, frictionRawValue2); + } + } + public void Stop() { + Log.Information("停止防滑测试设备连接与轮询"); cancellationTokenSource?.Cancel(); try @@ -209,6 +280,10 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services lock (sync) { + pressureRawValue = pressureRaw; + frictionRawValue1 = friction1Raw; + frictionRawValue2 = friction2Raw; + hasAdcRawValues = true; verticalLoadN = pressure; horizontalFrictionN = friction; lastError = string.Empty; @@ -220,6 +295,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services } catch (Exception ex) { + LogPollingError("ADC", ex, ref lastAdcErrorLoggedAt); SetConnected(false, ex.Message); Thread.Sleep(250); } @@ -255,6 +331,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services } catch (Exception ex) { + LogPollingError("PLC", ex, ref lastPlcErrorLoggedAt); SetConnected(false, ex.Message); Thread.Sleep(250); } @@ -263,6 +340,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services private async Task PulseCoilAsync(ushort coil) { + Log.Information("发送 PLC 脉冲线圈:M{Coil}", coil); await WriteCoilAsync(coil, true); await Task.Delay(80); await WriteCoilAsync(coil, false); @@ -274,6 +352,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services var master = plcMaster ?? throw new InvalidOperationException("PLC 未连接"); var current = master.ReadCoils(SlaveId, coil, 1)[0]; master.WriteSingleCoil(SlaveId, coil, !current); + Log.Information("切换 PLC 线圈:M{Coil}, Before={Before}, After={After}", coil, current, !current); }); private Task WriteCoilAsync(ushort coil, bool value) => @@ -281,6 +360,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services { var master = plcMaster ?? throw new InvalidOperationException("PLC 未连接"); master.WriteSingleCoil(SlaveId, coil, value); + Log.Debug("写入 PLC 线圈:M{Coil}={Value}", coil, value); }); private Task WriteFloatRegisterAsync(ushort register, double value) => @@ -288,8 +368,27 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.Services { var master = plcMaster ?? throw new InvalidOperationException("PLC 未连接"); master.WriteMultipleRegisters(SlaveId, register, SplitFloatToUShortArray((float)value)); + Log.Information("写入 PLC 浮点寄存器:D{Register}={Value:F3}", register, value); }); + private void LogPollingError(string source, Exception exception, ref DateTime lastLoggedAt) + { + var now = DateTime.UtcNow; + if (now - lastLoggedAt < TimeSpan.FromSeconds(5)) + { + return; + } + + lastLoggedAt = now; + Log.Error( + exception, + "{Source} 轮询失败:PLC={PlcPort}, ADC={AdcPort}, BaudRate={BaudRate}", + source, + settings.PlcPortName, + settings.AdcPortName, + settings.BaudRate); + } + private void SetConnected(bool connected, string error) { lock (sync) diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs index 5bc6674..aeb3188 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/ViewModels/MainWindowViewModel.cs @@ -7,6 +7,7 @@ using LiveChartsCore; using LiveChartsCore.Defaults; using LiveChartsCore.SkiaSharpView; using LiveChartsCore.SkiaSharpView.Painting; +using Serilog; using SkiaSharp; using System; using System.Collections.Generic; @@ -215,6 +216,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel public MainWindowViewModel() { + Log.Information("初始化主页面 ViewModel"); Series = [ CreateLineSeries("垂直压力(N)", verticalLoadPoints, "#DC2626", 0, 0.65), @@ -226,6 +228,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel LoadDeviceSettings(); UpdateTargetLoad(); deviceService.Start(CurrentSettings()); + _ = LoadPlcParametersAsync(); refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(33) }; refreshTimer.Tick += (_, _) => RefreshFromDevice(); @@ -263,6 +266,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel var points = currentRun.Count > 0 ? currentRun.ToList() : lastCompletedRun; if (points.Count == 0) { + Log.Warning("请求导出 Excel 时没有可导出的实时采样数据:TestNumber={TestNumber}", TestNumber); CurrentStatus = "没有可导出的实时采样数据,请先完成一次测试"; return; } @@ -292,6 +296,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel } catch (Exception ex) { + Log.Error(ex, "Excel 导出失败:TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, points.Count); CurrentStatus = $"Excel 导出失败:{ex.Message}"; } } @@ -336,6 +341,41 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel deviceService.UpdateSettings(CurrentSettings()); } + [RelayCommand] + private void CalibrateNormalPressureZero() + { + try + { + var zero = deviceService.CaptureCurrentAdcZero(); + NormalPressureZero = zero.NormalPressureZero.ToString(CultureInfo.InvariantCulture); + SaveAndApplySettings(); + CurrentStatus = "正压力零点已按当前 ADC 原始值采集"; + } + catch (Exception ex) + { + Log.Error(ex, "正压力零点采集失败"); + CurrentStatus = $"正压力零点采集失败:{ex.Message}"; + } + } + + [RelayCommand] + private void CalibrateFrictionZero() + { + try + { + var zero = deviceService.CaptureCurrentAdcZero(); + FrictionZero1 = zero.FrictionZero1.ToString(CultureInfo.InvariantCulture); + FrictionZero2 = zero.FrictionZero2.ToString(CultureInfo.InvariantCulture); + SaveAndApplySettings(); + CurrentStatus = "摩擦零点已按当前 ADC 原始值采集"; + } + catch (Exception ex) + { + Log.Error(ex, "摩擦零点采集失败"); + CurrentStatus = $"摩擦零点采集失败:{ex.Message}"; + } + } + partial void OnUploadProgressChanged(int value) => OnPropertyChanged(nameof(UploadProgressText)); partial void OnManualSpeedChanged(string value) @@ -434,6 +474,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel runStopwatch.Restart(); UploadProgress = 0; CurrentStatus = "测试运行:按标准采集垂直载荷、摩擦力、位移与摩擦系数"; + Log.Information("测试开始:TestNumber={TestNumber}, TargetLoad={TargetLoad}, TestSpeed={TestSpeed}", TestNumber, TargetLoadText, TestSpeedText); } private void RecordPoint(SlipDeviceSnapshot device) @@ -466,6 +507,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel runStopwatch.Stop(); if (currentRun.Count < 3) { + Log.Warning("测试停止但采样点不足:TestNumber={TestNumber}, PointCount={PointCount}", TestNumber, currentRun.Count); CurrentStatus = "测试已停止,但有效采样点不足,未生成结果"; return; } @@ -503,6 +545,13 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel CurrentStatus = verdict == "有效" ? "测试完成:已按标准生成静/动摩擦系数" : "测试完成:最近三次结果差异超过 10%,建议重新测试"; + Log.Information( + "测试完成:TestNumber={TestNumber}, PointCount={PointCount}, StaticCoefficient={StaticCoefficient:F3}, DynamicCoefficient={DynamicCoefficient:F3}, Verdict={Verdict}", + TestNumber, + currentRun.Count, + staticCoefficientValue, + dynamicCoefficientValue, + verdict); } private bool NeedsRetest(double staticCoefficientValue, double dynamicCoefficientValue) @@ -571,6 +620,7 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel } catch (Exception ex) { + Log.Error(ex, "设备指令失败:{SuccessMessage}", successMessage); CurrentStatus = $"设备指令失败:{ex.Message}"; } } @@ -591,6 +641,25 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel deviceService.UpdateSettings(CurrentSettings()); } + private async Task LoadPlcParametersAsync() + { + try + { + var parameters = await deviceService.ReadDeviceParametersAsync(); + isLoadingDeviceSettings = true; + ManualSpeed = parameters.ManualSpeed.ToString("F2", CultureInfo.InvariantCulture); + ManualDisplacement = parameters.ManualDisplacement.ToString("F2", CultureInfo.InvariantCulture); + TestSpeed = parameters.TestSpeed.ToString("F2", CultureInfo.InvariantCulture); + isLoadingDeviceSettings = false; + SaveAndApplySettings(); + } + catch (Exception ex) + { + isLoadingDeviceSettings = false; + Log.Warning(ex, "启动时读取 PLC 参数失败,将使用本地保存的设备设置"); + } + } + private void LoadDeviceSettings() { if (!File.Exists(DeviceSettingsPath)) @@ -621,8 +690,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel AdcPortName = settings.AdcPortName ?? AdcPortName; BaudRate = settings.BaudRate > 0 ? settings.BaudRate : BaudRate; } - catch + catch (Exception ex) { + Log.Warning(ex, "读取设备设置失败:Path={Path}", DeviceSettingsPath); } finally { @@ -643,8 +713,9 @@ namespace Footwear_Test_methodsfor_wholeshoe_Slipresistanceperformance.ViewModel var json = JsonSerializer.Serialize(CurrentSettings(), new JsonSerializerOptions { WriteIndented = true }); File.WriteAllText(DeviceSettingsPath, json); } - catch + catch (Exception ex) { + Log.Warning(ex, "保存设备设置失败:Path={Path}", DeviceSettingsPath); } } diff --git a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml index 5eed7ba..56203c1 100644 --- a/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml +++ b/Footwear Test methodsfor wholeshoe Slipresistanceperformance/Views/MainWindow.axaml @@ -328,7 +328,7 @@