From d4562e600ed67404463b4ec0a97d46dc1ba8e7d6 Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Sat, 4 Oct 2025 20:46:39 +0800 Subject: [PATCH] =?UTF-8?q?1=20feat:=20=E6=B7=BB=E5=8A=A0=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=AF=BC=E5=85=A5=E6=A8=A1=E6=9D=BF=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=92=8C=E5=B7=A5=E5=8E=82=E6=A8=A1=E5=BC=8F=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=20=20=20=20=202=20=20=20=20=203=20-=20=20=20=20=20=20=20?= =?UTF-8?q?=E5=9C=A8AppSettings=E4=B8=AD=E6=B7=BB=E5=8A=A0VariableImportTe?= =?UTF-8?q?mplate=E9=85=8D=E7=BD=AE=E9=A1=B9=EF=BC=8C=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=8F=98=E9=87=8F=E5=AF=BC=E5=85=A5=E7=9A=84?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=8F=82=E6=95=B0=EF=BC=88IsActive=E3=80=81P?= =?UTF-8?q?ollingIn=20=20=20=20=20=20=20terval=E3=80=81IsHistoryEnabled?= =?UTF-8?q?=E3=80=81HistoryDeadband=EF=BC=89=20=20=20=20=204=20-=20?= =?UTF-8?q?=E4=BF=AE=E6=94=B9AppSettings.Load()=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20=20=20=20=205=20-=20=20=20=20=20=20=20=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0IVariableItemViewModelFactory=E5=92=8CVariableItemView?= =?UTF-8?q?ModelFactory=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=B7=A5=E5=8E=82?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=88=9B=E5=BB=BAVariableItemVie=20=20=20=20?= =?UTF-8?q?=20=20=20wModel=E5=AE=9E=E4=BE=8B=20=20=20=20=206=20-=20?= =?UTF-8?q?=E5=9C=A8ImportOpcUaDialogViewModel=E4=B8=AD=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=B7=A5=E5=8E=82=E5=88=9B=E5=BB=BAVariableItemViewModel?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=EF=BC=8C=E4=BB=A5=E5=BA=94=E7=94=A8=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E9=85=8D=E7=BD=AE=20=20=20=20=207=20-=20=20=20=20=20?= =?UTF-8?q?=20=20=E5=9C=A8SettingViewModel=E5=92=8CSettingView=E4=B8=AD?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=98=E9=87=8F=E5=AF=BC=E5=85=A5=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=95=8C=E9=9D=A2=E5=92=8C=E7=9B=B8=E5=85=B3=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=EF=BC=88VariablePollingInterval=E3=80=81Variab=20=20?= =?UTF-8?q?=20=20=20=20=20leIsActive=E3=80=81VariableIsHistoryEnabled?= =?UTF-8?q?=E3=80=81VariableHistoryDeadband=EF=BC=89=20=20=20=20=208=20-?= =?UTF-8?q?=20=E7=A7=BB=E9=99=A4VariableItemViewModel=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=B8=AD=E7=9A=84=E8=BD=AE=E8=AF=A2=E9=97=B4?= =?UTF-8?q?=E9=9A=94=E9=BB=98=E8=AE=A4=E5=80=BC=E8=AE=BE=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E7=94=B1=E5=B7=A5=E5=8E=82=E6=A8=A1=E5=BC=8F=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=20=20=20=20=209=20-=20=E4=BC=98=E5=8C=96SplashViewMod?= =?UTF-8?q?el=E4=B8=AD=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E9=80=BB?= =?UTF-8?q?=E8=BE=91=20=20=20=2010=20-=20=E7=A7=BB=E9=99=A4MainView.xaml.c?= =?UTF-8?q?s=E4=B8=AD=E5=B7=B2=E6=B3=A8=E9=87=8A=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=20=20=20=2011=20-=20=E8=B0=83=E6=95=B4VariableTableVi?= =?UTF-8?q?ew.xaml=E7=9A=84UI=E5=B8=83=E5=B1=80=E5=92=8C=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E7=BB=93=E6=9E=84=20=20=20=2012=20-=20=E6=B3=A8=E5=86=8CIVaria?= =?UTF-8?q?bleItemViewModelFactory=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 这些修改主要实现了几个关键功能: 1. 引入了工厂模式来创建VariableItemViewModel实例,确保所有新创建的变量项都应用默认配置 2. 添加了变量导入模板设置,用户可以在设置界面自定义导入变量的默认属性 3. 对相关UI进行了调整和优化 --- DMS.Application/Configurations/AppSettings.cs | 47 ++++-- DMS.WPF/App.xaml.cs | 4 + .../Factories/VariableItemViewModelFactory.cs | 55 +++++++ .../Dialogs/ImportOpcUaDialogViewModel.cs | 30 ++-- .../ViewModels/Items/VariableItemViewModel.cs | 3 - DMS.WPF/ViewModels/SettingViewModel.cs | 52 +++++- DMS.WPF/ViewModels/SplashViewModel.cs | 5 +- DMS.WPF/ViewModels/VariableTableViewModel.cs | 3 +- DMS.WPF/Views/MainView.xaml.cs | 11 -- DMS.WPF/Views/SettingView.xaml | 19 ++- DMS.WPF/Views/VariableTableView.xaml | 153 +++++++++--------- 11 files changed, 249 insertions(+), 133 deletions(-) create mode 100644 DMS.WPF/Factories/VariableItemViewModelFactory.cs diff --git a/DMS.Application/Configurations/AppSettings.cs b/DMS.Application/Configurations/AppSettings.cs index ba83bff..eb56bee 100644 --- a/DMS.Application/Configurations/AppSettings.cs +++ b/DMS.Application/Configurations/AppSettings.cs @@ -3,10 +3,15 @@ using Newtonsoft.Json; namespace DMS.Application.Configurations { - + public class AppSettings { + private static readonly string SettingsFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigJsonFileName); + + private const string ConfigJsonFileName = "dms_config.json"; + + public class Database { public string DbType { get; set; } = "MySql"; @@ -16,37 +21,47 @@ namespace DMS.Application.Configurations public string Password { get; set; } = "Pgw15221236646"; public string DbName { get; set; } = "dms_test"; } - - + + public Database Db { get; set; } = new Database(); + + public Variable VariableImportTemplate = new Variable() + { + IsActive = true, + PollingInterval = 30000, + IsHistoryEnabled = true, + HistoryDeadband = 0 + }; + public string Theme { get; set; } = "跟随系统"; - public bool EnableS7Service { get; set; } = true; - public bool EnableMqttService { get; set; } = true; - public bool EnableOpcUaService { get; set; } = true; public bool MinimizeToTrayOnClose { get; set; } = true; - public List Menus { get; set; } = new List(); - public int DefaultPollingInterval { get; set; } = 30000; // 默认轮询间隔30秒 - - private static readonly string SettingsFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigJsonFileName); - private const string ConfigJsonFileName = "dms_config.json"; - public AppSettings? Load() + public void Load() { if (File.Exists(SettingsFilePath)) { string json = File.ReadAllText(SettingsFilePath); AppSettings? appSettings = JsonConvert.DeserializeObject(json); - return appSettings ?? throw new InvalidOperationException("加载配置文件出现了错误。"); + if (appSettings != null) + { + this.Db= appSettings.Db; + this.VariableImportTemplate = appSettings.VariableImportTemplate; + this.Theme=appSettings.Theme; + this.MinimizeToTrayOnClose=appSettings.MinimizeToTrayOnClose; + } + else + { + throw new InvalidOperationException("加载配置文件出现了错误。"); + } } - return null; } public void Save() { - string json = JsonConvert.SerializeObject(this, Formatting.Indented); - File.WriteAllText(SettingsFilePath, json); + string json = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(SettingsFilePath, json); } public string ToConnectionString() diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index 903f7e6..f6ef457 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -25,6 +25,7 @@ using DMS.Infrastructure.Services.Mqtt; using DMS.Infrastructure.Services.OpcUa; using DMS.Infrastructure.Services.S7; using DMS.WPF.Converters; +using DMS.WPF.Factories; using DMS.WPF.Helper; using DMS.WPF.Interfaces; using DMS.WPF.Logging; @@ -346,6 +347,9 @@ public partial class App : System.Windows.Application services.AddTransient(); services.AddTransient(); services.AddTransient(); // 注册 TriggerEditorViewModel + + // 注册工厂 + services.AddTransient(); // 注册View视图 services.AddSingleton(); diff --git a/DMS.WPF/Factories/VariableItemViewModelFactory.cs b/DMS.WPF/Factories/VariableItemViewModelFactory.cs new file mode 100644 index 0000000..46ad0a5 --- /dev/null +++ b/DMS.WPF/Factories/VariableItemViewModelFactory.cs @@ -0,0 +1,55 @@ +using DMS.Application.DTOs; +using DMS.WPF.ViewModels.Items; +using DMS.Application.Configurations; +using Microsoft.Extensions.DependencyInjection; + +namespace DMS.WPF.Factories +{ + /// + /// VariableItemViewModel工厂类 + /// 专门用于构建VariableItemViewModel实例 + /// + public interface IVariableItemViewModelFactory + { + /// + /// 从VariableDto创建VariableItemViewModel实例 + /// + /// 变量数据传输对象 + /// VariableItemViewModel实例 + VariableItemViewModel CreateNewVariableItemViewModel(); + + } + + public class VariableItemViewModelFactory : IVariableItemViewModelFactory + { + private readonly IServiceProvider _serviceProvider; + private readonly AppSettings _appSettings; + + public VariableItemViewModelFactory(AppSettings appSettings) + { + _appSettings = appSettings; + } + + /// + /// 从VariableDto创建VariableItemViewModel实例 + /// + /// 变量数据传输对象 + /// VariableItemViewModel实例 + public VariableItemViewModel CreateNewVariableItemViewModel() + { + + var viewModel = new VariableItemViewModel() + { + + IsActive = _appSettings.VariableImportTemplate.IsActive, + IsHistoryEnabled = _appSettings.VariableImportTemplate.IsHistoryEnabled, + HistoryDeadband = _appSettings.VariableImportTemplate.HistoryDeadband, + PollingInterval = _appSettings.VariableImportTemplate.PollingInterval, + }; + + + return viewModel; + } + + } +} \ No newline at end of file diff --git a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs index c28b371..77bc692 100644 --- a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs +++ b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs @@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.Input; using DMS.Core.Enums; using DMS.Infrastructure.Interfaces.Services; using DMS.Infrastructure.Models; +using DMS.WPF.Factories; using DMS.WPF.Interfaces; using DMS.WPF.Services; using DMS.WPF.ViewModels.Items; @@ -79,17 +80,18 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase private readonly IOpcUaService _opcUaService; - + private readonly IVariableItemViewModelFactory _variableItemViewModelFactory; + /// /// 对象映射器实例 /// private readonly IMapper _mapper; - + /// /// 取消令牌源,用于取消长时间运行的操作 /// private readonly CancellationTokenSource _cancellationTokenSource; - + /// /// 通知服务实例 /// @@ -102,9 +104,11 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBaseOPC UA服务接口实例 /// 对象映射器实例 /// 通知服务实例 - public ImportOpcUaDialogViewModel(IOpcUaService opcUaService, IMapper mapper, INotificationService notificationService) + public ImportOpcUaDialogViewModel(IOpcUaService opcUaService, IVariableItemViewModelFactory variableItemViewModelFactory, + IMapper mapper, INotificationService notificationService) { _opcUaService = opcUaService; + _variableItemViewModelFactory = variableItemViewModelFactory; _mapper = mapper; _notificationService = notificationService; // 初始化根节点 @@ -319,7 +323,7 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase(node)); - + // 再次检查是否有取消请求 _cancellationTokenSource.Token.ThrowIfCancellationRequested(); @@ -332,15 +336,15 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase().DefaultPollingInterval; // 默认值,可通过外部设置覆盖 } diff --git a/DMS.WPF/ViewModels/SettingViewModel.cs b/DMS.WPF/ViewModels/SettingViewModel.cs index 5d46b0e..7c1ff25 100644 --- a/DMS.WPF/ViewModels/SettingViewModel.cs +++ b/DMS.WPF/ViewModels/SettingViewModel.cs @@ -135,19 +135,63 @@ public partial class SettingViewModel : ViewModelBase } } - public int DefaultPollingInterval + public int VariablePollingInterval { - get => _settings.DefaultPollingInterval; + get => _settings.VariableImportTemplate.PollingInterval; set { - if (_settings.DefaultPollingInterval != value) + if (_settings.VariableImportTemplate.PollingInterval != value) { - _settings.DefaultPollingInterval = value; + _settings.VariableImportTemplate.PollingInterval = value; OnPropertyChanged(); _settings.Save(); } } } + + public bool VariableIsActive + { + get => _settings.VariableImportTemplate.IsActive; + set + { + if (_settings.VariableImportTemplate.IsActive != value) + { + _settings.VariableImportTemplate.IsActive = value; + OnPropertyChanged(); + _settings.Save(); + } + } + } + + public bool VariableIsHistoryEnabled + { + get => _settings.VariableImportTemplate.IsHistoryEnabled; + set + { + if (_settings.VariableImportTemplate.IsHistoryEnabled != value) + { + _settings.VariableImportTemplate.IsHistoryEnabled = value; + OnPropertyChanged(); + _settings.Save(); + } + } + } + + public double VariableHistoryDeadband + { + get => _settings.VariableImportTemplate.HistoryDeadband; + set + { + if (_settings.VariableImportTemplate.HistoryDeadband != value) + { + _settings.VariableImportTemplate.HistoryDeadband = value; + OnPropertyChanged(); + _settings.Save(); + } + } + } + + [RelayCommand] private async Task TestConnection() diff --git a/DMS.WPF/ViewModels/SplashViewModel.cs b/DMS.WPF/ViewModels/SplashViewModel.cs index 39aefe6..e0e33b7 100644 --- a/DMS.WPF/ViewModels/SplashViewModel.cs +++ b/DMS.WPF/ViewModels/SplashViewModel.cs @@ -52,10 +52,7 @@ public partial class SplashViewModel : ObservableObject try { LoadingMessage = "正在加载系统配置..."; - if (_appSettings.Load() == null) - { - //程序第一次启动 - } + _appSettings.Load(); _logger.LogInformation("正在初始化数据库..."); LoadingMessage = "正在初始化数据库..."; diff --git a/DMS.WPF/ViewModels/VariableTableViewModel.cs b/DMS.WPF/ViewModels/VariableTableViewModel.cs index d8f3798..1f15479 100644 --- a/DMS.WPF/ViewModels/VariableTableViewModel.cs +++ b/DMS.WPF/ViewModels/VariableTableViewModel.cs @@ -11,7 +11,6 @@ using DMS.Core.Events; using DMS.Core.Models; using DMS.WPF.Interfaces; using DMS.WPF.ViewModels.Dialogs; -using DMS.WPF.ViewModels.Dialogs; using DMS.WPF.ViewModels.Items; using Microsoft.Extensions.DependencyInjection; using ObservableCollections; @@ -329,6 +328,8 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable return; // 用户取消或没有选择任何变量 } + + // 将导入的变量转换为DTO并设置必要的属性 var importedVariableDtos = _mapper.Map>(importedVariables); foreach (var variableDto in importedVariableDtos) diff --git a/DMS.WPF/Views/MainView.xaml.cs b/DMS.WPF/Views/MainView.xaml.cs index f19a269..6a0d4fc 100644 --- a/DMS.WPF/Views/MainView.xaml.cs +++ b/DMS.WPF/Views/MainView.xaml.cs @@ -31,17 +31,6 @@ public partial class MainView : Window private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) { - // var settings = Config.AppSettings.Load(); - // if (settings.MinimizeToTrayOnClose) - // { - // // Hide the window instead of closing it - // e.Cancel = true; - // Hide(); - // } - // else - // { - // Application.Current.Shutdown(); - // } } public void ShowApplication() diff --git a/DMS.WPF/Views/SettingView.xaml b/DMS.WPF/Views/SettingView.xaml index 1e674fa..b16fe09 100644 --- a/DMS.WPF/Views/SettingView.xaml +++ b/DMS.WPF/Views/SettingView.xaml @@ -84,10 +84,25 @@ - + - + + + + + + + + + + + + + + + + diff --git a/DMS.WPF/Views/VariableTableView.xaml b/DMS.WPF/Views/VariableTableView.xaml index 456c144..95a673f 100644 --- a/DMS.WPF/Views/VariableTableView.xaml +++ b/DMS.WPF/Views/VariableTableView.xaml @@ -41,85 +41,86 @@ - - + + - - + + - - - - + - - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - + Command="{Binding ImprotFromTiaVarTableCommand}" + Label="从TIA变量表导入" + Visibility="{Binding IsS7ProtocolSelected, Converter={StaticResource BooleanToVisibilityConverter}}"> + + + - - + + + + + + + + + + + + + + + + + + + + + - + - + @@ -235,7 +234,7 @@ - + - - + + - - + + @@ -319,7 +314,7 @@ - + @@ -346,13 +341,13 @@ Header="更新时间" IsReadOnly="True" /> - + - +