From f80a1669fba03603c40f4445c54e5e6644a6ab0b Mon Sep 17 00:00:00 2001 From: "David P.G" Date: Mon, 25 Aug 2025 21:26:18 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=BF=9E=E6=8E=A5OpcUa?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interfaces/Services/IOpcUaService.cs | 14 +--- DMS.Infrastructure/Services/OpcUaService.cs | 59 ++++------------ DMS.WPF/Services/DialogService.cs | 1 + DMS.WPF/Services/NavgatorServices.cs | 68 ------------------- DMS.WPF/Services/NavigationService.cs | 16 +++-- DMS.WPF/ViewModels/DevicesViewModel.cs | 4 +- .../Dialogs/ImportOpcUaDialogViewModel.cs | 41 +++++++---- DMS.WPF/ViewModels/MqttsViewModel.cs | 1 - DMS.WPF/ViewModels/VariableTableViewModel.cs | 2 +- DMS.WPF/Views/Dialogs/ImportOpcUaDialog.xaml | 27 +++++++- .../Views/Dialogs/ImportOpcUaDialog.xaml.cs | 8 +-- 11 files changed, 86 insertions(+), 155 deletions(-) delete mode 100644 DMS.WPF/Services/NavgatorServices.cs diff --git a/DMS.Infrastructure/Interfaces/Services/IOpcUaService.cs b/DMS.Infrastructure/Interfaces/Services/IOpcUaService.cs index 1b83d11..b365ba3 100644 --- a/DMS.Infrastructure/Interfaces/Services/IOpcUaService.cs +++ b/DMS.Infrastructure/Interfaces/Services/IOpcUaService.cs @@ -9,25 +9,15 @@ namespace DMS.Infrastructure.Interfaces.Services { public interface IOpcUaService { - /// - /// 创建 OPC UA 会话 - /// - /// OPC UA 服务器地址 - /// 取消令牌 - /// - public Task CreateSession(string opcUaServerUrl, CancellationToken stoppingToken = default); /// /// 连接到 OPC UA 服务器(异步) /// /// 取消令牌 /// - public Task ConnectAsync(CancellationToken stoppingToken = default); + public Task ConnectAsync(string opcUaServerUrl,CancellationToken stoppingToken = default); + - /// - /// 连接到 OPC UA 服务器(同步) - /// - public void Connect(); /// /// 断开 OPC UA 服务器连接 diff --git a/DMS.Infrastructure/Services/OpcUaService.cs b/DMS.Infrastructure/Services/OpcUaService.cs index b469ac1..8f95a9d 100644 --- a/DMS.Infrastructure/Services/OpcUaService.cs +++ b/DMS.Infrastructure/Services/OpcUaService.cs @@ -14,7 +14,7 @@ namespace DMS.Infrastructure.Services public class OpcUaService : IOpcUaService { private Session? _session; - private string? _serverUrl; + private string _serverUrl; /// /// 创建 OPC UA 会话 @@ -22,17 +22,14 @@ namespace DMS.Infrastructure.Services /// OPC UA 服务器地址 /// 取消令牌 /// - public async Task CreateSession(string opcUaServerUrl, CancellationToken stoppingToken = default) + public async Task CreateSession( CancellationToken stoppingToken = default) { - if (string.IsNullOrEmpty(opcUaServerUrl)) - { - throw new ArgumentException("OPC UA server URL cannot be null or empty.", nameof(opcUaServerUrl)); - } + try { - _session = await OpcUaHelper.CreateOpcUaSessionAsync(opcUaServerUrl, stoppingToken); - _serverUrl = opcUaServerUrl; + _session = await OpcUaHelper.CreateOpcUaSessionAsync(_serverUrl, stoppingToken); + } catch (Exception ex) { @@ -43,13 +40,18 @@ namespace DMS.Infrastructure.Services /// /// 连接到 OPC UA 服务器 /// - public async Task ConnectAsync(CancellationToken stoppingToken = default) + public async Task ConnectAsync(string opcUaServerUrl, CancellationToken stoppingToken = default) { + _serverUrl = opcUaServerUrl; + if (string.IsNullOrEmpty(opcUaServerUrl)) + { + throw new ArgumentException("OPC UA server URL cannot be null or empty.", nameof(opcUaServerUrl)); + } if (string.IsNullOrEmpty(_serverUrl)) { throw new InvalidOperationException("Server URL is not set. Please call CreateSession first."); } - + // 如果已经连接,直接返回 if (_session?.Connected == true) { @@ -57,43 +59,10 @@ namespace DMS.Infrastructure.Services } // 重新创建会话 - await CreateSession(_serverUrl, stoppingToken); + await CreateSession( stoppingToken); } - /// - /// 连接到 OPC UA 服务器(同步版本,用于向后兼容) - /// - public void Connect() - { - if (string.IsNullOrEmpty(_serverUrl)) - { - throw new InvalidOperationException("Server URL is not set. Please call CreateSession first."); - } - - // 如果已经连接,直接返回 - if (_session?.Connected == true) - { - return; - } - - // 检查会话是否存在但未连接 - if (_session != null) - { - // 尝试重新激活会话 - try - { - _session.Reconnect(); - return; - } - catch - { - // 如果重新连接失败,继续到重新创建会话的步骤 - } - } - - // 如果没有会话或重新连接失败,抛出异常提示需要调用 CreateSession - throw new InvalidOperationException("Session is not created or connection lost. Please call CreateSession first."); - } + /// /// 断开 OPC UA 服务器连接 diff --git a/DMS.WPF/Services/DialogService.cs b/DMS.WPF/Services/DialogService.cs index 2cd6014..d1f31f1 100644 --- a/DMS.WPF/Services/DialogService.cs +++ b/DMS.WPF/Services/DialogService.cs @@ -18,6 +18,7 @@ namespace DMS.WPF.Services { typeof(ConfirmDialogViewModel), typeof(ConfirmDialog) }, { typeof(VariableTableDialogViewModel), typeof(VariableTableDialog) }, { typeof(ImportExcelDialogViewModel), typeof(ImportExcelDialog) }, + { typeof(ImportOpcUaDialogViewModel), typeof(ImportOpcUaDialog) }, { typeof(VariableDialogViewModel), typeof(VariableDialog) }, // { typeof(MqttDialogViewModel), typeof(MqttDialog) }, // Add other mappings here // ... other dialogs diff --git a/DMS.WPF/Services/NavgatorServices.cs b/DMS.WPF/Services/NavgatorServices.cs deleted file mode 100644 index ff9fe88..0000000 --- a/DMS.WPF/Services/NavgatorServices.cs +++ /dev/null @@ -1,68 +0,0 @@ -using CommunityToolkit.Mvvm.ComponentModel; -using CommunityToolkit.Mvvm.Messaging; -using DMS.Helper; -using DMS.Message; -using DMS.WPF.ViewModels; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using DMS.Core.Enums; - -namespace DMS.Services; - -public partial class NavgatorServices : ObservableRecipient, IRecipient -{ - // [ObservableProperty] - private ViewModelBase currentViewModel; - - public NavgatorServices() - { - IsActive = true; - } - - // partial void OnCurrentViewModelChanging(ViewModelBase viewModel) - // { - // viewModel?.OnLoading(); - // } - // - // partial void OnCurrentViewModelChanged(ViewModelBase viewModel) - // { - // OnViewModelChanged?.Invoke(); - // viewModel?.OnLoaded(); - // } - - public ViewModelBase CurrentViewModel - { - get => currentViewModel; - set { currentViewModel = value; } - } - - - public async void Receive(NavgatorMessage message) - { - try - { - ViewModelBase nextViewModel = message.Value; - //如果OnExit返回False终止跳转 - - if (currentViewModel != null) - { - var isExit = await currentViewModel.OnExitAsync(); - if (!isExit) - { - return; - } - } - - nextViewModel?.OnLoading(); - CurrentViewModel = message.Value; - OnViewModelChanged?.Invoke(); - currentViewModel?.OnLoaded(); - } - catch (Exception e) - { - NotificationHelper.ShowError($"切换视图时发生了错误:{e.Message}", e); - } - } - - public event Action OnViewModelChanged; -} \ No newline at end of file diff --git a/DMS.WPF/Services/NavigationService.cs b/DMS.WPF/Services/NavigationService.cs index 2b71e94..f29071c 100644 --- a/DMS.WPF/Services/NavigationService.cs +++ b/DMS.WPF/Services/NavigationService.cs @@ -1,14 +1,15 @@ // 文件: DMS.WPF/Services/NavigationService.cs +using DMS.Helper; +using DMS.ViewModels; using DMS.WPF.ViewModels; +using DMS.WPF.ViewModels.Items; +using DMS.WPF.Views; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows; -using DMS.ViewModels; -using DMS.WPF.ViewModels.Items; -using DMS.WPF.Views; namespace DMS.WPF.Services; @@ -39,6 +40,13 @@ public class NavigationService : INavigationService var mainViewModel = App.Current.Services.GetRequiredService(); var viewModel = GetViewModelByKey(menu.TargetViewKey); + if (viewModel == null) + { + + NotificationHelper.ShowError($"切换界面失败,没有找到界面:{menu.TargetViewKey}"); + return; + } + if (viewModel is INavigatable navigatableViewModel) { @@ -70,7 +78,7 @@ public class NavigationService : INavigationService case "SettingView": return App.Current.Services.GetRequiredService(); default: - throw new KeyNotFoundException($"未找到与键 '{key}' 关联的视图模型类型。请检查 NavigationService 的映射配置。"); + return null; } } } \ No newline at end of file diff --git a/DMS.WPF/ViewModels/DevicesViewModel.cs b/DMS.WPF/ViewModels/DevicesViewModel.cs index 0a755da..27f4e72 100644 --- a/DMS.WPF/ViewModels/DevicesViewModel.cs +++ b/DMS.WPF/ViewModels/DevicesViewModel.cs @@ -106,8 +106,8 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable { Header = device.Name, Icon = SegoeFluentIcons.Devices2.Glyph, - TargetViewKey = "DevicesView" - }; + TargetViewKey = "DeviceDetailView" + }; if (device.IsAddDefVarTable) { dto.VariableTable = new VariableTableDto() diff --git a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs index b15d7bb..328ca5b 100644 --- a/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs +++ b/DMS.WPF/ViewModels/Dialogs/ImportOpcUaDialogViewModel.cs @@ -2,7 +2,9 @@ using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using DMS.Core.Models; using DMS.Helper; +using DMS.Infrastructure.Interfaces.Services; using DMS.WPF.ViewModels.Items; +using Opc.Ua; using Opc.Ua.Client; using System.Collections.ObjectModel; @@ -27,14 +29,25 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase(); SelectedNodeVariables = new ObservableCollection(); - // Automatically connect when the ViewModel is created - //ConnectC.Execute(null); + this._opcUaService = opcUaService; + + _cancellationTokenSource=new CancellationTokenSource(); } @@ -44,27 +57,29 @@ public partial class ImportOpcUaDialogViewModel : DialogViewModelBase _logger; - private readonly NavgatorServices _navgatorServices; [ObservableProperty] private ObservableCollection _mqtts; diff --git a/DMS.WPF/ViewModels/VariableTableViewModel.cs b/DMS.WPF/ViewModels/VariableTableViewModel.cs index b74ae32..4f8cfd5 100644 --- a/DMS.WPF/ViewModels/VariableTableViewModel.cs +++ b/DMS.WPF/ViewModels/VariableTableViewModel.cs @@ -286,7 +286,7 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable } // 显示OPC UA导入对话框,让用户选择要导入的变量 - ImportOpcUaDialogViewModel importOpcUaDialogViewModel = new ImportOpcUaDialogViewModel(); + ImportOpcUaDialogViewModel importOpcUaDialogViewModel = App.Current.Services.GetRequiredService() ; var importedVariables = await _dialogService.ShowDialogAsync(importOpcUaDialogViewModel); if (importedVariables == null || !importedVariables.Any()) { diff --git a/DMS.WPF/Views/Dialogs/ImportOpcUaDialog.xaml b/DMS.WPF/Views/Dialogs/ImportOpcUaDialog.xaml index 3acf79a..edd265a 100644 --- a/DMS.WPF/Views/Dialogs/ImportOpcUaDialog.xaml +++ b/DMS.WPF/Views/Dialogs/ImportOpcUaDialog.xaml @@ -15,6 +15,7 @@ mc:Ignorable="d"> + @@ -22,9 +23,31 @@ + + + +