diff --git a/Data/Entities/DbVariableData.cs b/Data/Entities/DbVariableData.cs
index e1daea4..742a7b0 100644
--- a/Data/Entities/DbVariableData.cs
+++ b/Data/Entities/DbVariableData.cs
@@ -29,6 +29,7 @@ public class DbVariableData
///
/// 节点ID,用于标识变量在设备或系统中的唯一路径。
///
+ [SugarColumn(IsNullable = true)]
public string S7Address { get; set; } = String.Empty;
///
@@ -94,7 +95,8 @@ public class DbVariableData
///
/// 轮询级别,例如1秒、5秒等。
///
- [SugarColumn(ColumnDataType = "varchar(20)", SqlParameterDbType = typeof(EnumToStringConvert))]
+
+ [SugarColumn(ColumnDataType = "varchar(20)",IsNullable =true, SqlParameterDbType = typeof(EnumToStringConvert))]
public PollLevelType PollLevelType { get; set; }
///
diff --git a/Models/OpcUaNode.cs b/Models/OpcUaNode.cs
new file mode 100644
index 0000000..449dc6d
--- /dev/null
+++ b/Models/OpcUaNode.cs
@@ -0,0 +1,73 @@
+using System.Collections.ObjectModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Opc.Ua;
+
+namespace PMSWPF.Models;
+
+///
+/// 表示OPC UA节点,用于构建节点树。
+///
+public partial class OpcUaNode : ObservableObject
+{
+ ///
+ /// 节点的显示名称。
+ ///
+ public string DisplayName { get; set; }
+
+ ///
+ /// 节点的唯一标识符。
+ ///
+ public NodeId NodeId { get; set; }
+
+ ///
+ /// 节点的类型(例如,文件夹、变量)。
+ ///
+ public NodeType NodeType { get; set; }
+
+ ///
+ /// 子节点集合。
+ ///
+ [ObservableProperty]
+ private ObservableCollection _children;
+
+ ///
+ /// 指示节点是否已加载子节点。
+ ///
+ [ObservableProperty]
+ private bool _isLoaded;
+
+ ///
+ /// 指示节点是否正在加载子节点。
+ ///
+ [ObservableProperty]
+ private bool _isLoading;
+
+ ///
+ /// 节点的完整路径(可选,用于调试或显示)。
+ ///
+ public string Path { get; set; }
+
+ ///
+ /// 构造函数。
+ ///
+ /// 显示名称。
+ /// 节点ID。
+ /// 节点类型。
+ public OpcUaNode(string displayName, NodeId nodeId, NodeType nodeType)
+ {
+ DisplayName = displayName;
+ NodeId = nodeId;
+ NodeType = nodeType;
+ Children = new ObservableCollection();
+ }
+}
+
+///
+/// OPC UA节点类型枚举。
+///
+public enum NodeType
+{
+ Folder,
+ Object,
+ Variable
+}
diff --git a/PMSWPF.OpcUaClient.Config.xml b/PMSWPF.OpcUaClient.Config.xml
new file mode 100644
index 0000000..093bf05
--- /dev/null
+++ b/PMSWPF.OpcUaClient.Config.xml
@@ -0,0 +1,58 @@
+
+
+ PMSWPF OPC UA Client
+ urn:{System.Net.Dns.GetHostName()}:PMSWPF.OpcUaClient
+ 0
+
+
+
+ Directory
+ %CommonApplicationData%/OPC Foundation/CertificateStores/MachineDefault
+ CN=PMSWPF OPC UA Client, O=OPC Foundation, OU=UA Applications
+
+
+ Directory
+ %CommonApplicationData%/OPC Foundation/CertificateStores/UA Certificate Authorities
+
+
+ Directory
+ %CommonApplicationData%/OPC Foundation/CertificateStores/UA Applications
+
+
+ Directory
+ %CommonApplicationData%/OPC Foundation/CertificateStores/RejectedCertificates
+
+ true
+
+
+
+ 15000
+ 4194304
+ 65535
+ 65535
+ 4194304
+
+
+
+ 60000
+
+
+
+
+ en-US
+
+ 10000
+
+
+
+ ./Logs/OpcUaClient.log
+ true
+ 1023
+
+
+
+
\ No newline at end of file
diff --git a/PMSWPF.csproj b/PMSWPF.csproj
index e7fd96c..e9bdeec 100644
--- a/PMSWPF.csproj
+++ b/PMSWPF.csproj
@@ -37,6 +37,11 @@
Always
+
+
+ Always
+
+
diff --git a/Services/DialogService.cs b/Services/DialogService.cs
index e2a5f38..186b1a3 100644
--- a/Services/DialogService.cs
+++ b/Services/DialogService.cs
@@ -177,10 +177,14 @@ public class DialogService :IDialogService
var vm = new MqttSelectionDialogViewModel();
var dialog = new MqttSelectionDialog(vm);
var result = await dialog.ShowAsync();
- if (result == ContentDialogResult.Primary)
- {
- return vm.SelectedMqtt;
- }
- return null;
+ return result == ContentDialogResult.Primary ? vm.SelectedMqtt : null;
+ }
+
+ public async Task> ShowOpcUaImportDialog()
+ {
+ var vm= new OpcUaImportDialogViewModel();
+ var dialog = new OpcUaImportDialog(vm);
+ var result = await dialog.ShowAsync();
+ return result == ContentDialogResult.Primary ? vm.GetSelectedVariables().ToList() : null;
}
}
\ No newline at end of file
diff --git a/Services/IDialogService.cs b/Services/IDialogService.cs
index 925b516..ee4a203 100644
--- a/Services/IDialogService.cs
+++ b/Services/IDialogService.cs
@@ -22,4 +22,5 @@ public interface IDialogService
ContentDialog ShowProcessingDialog(string title, string message);
Task ShowPollLevelDialog(PollLevelType pollLevelType);
Task ShowMqttSelectionDialog();
+ Task> ShowOpcUaImportDialog();
}
\ No newline at end of file
diff --git a/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs b/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs
new file mode 100644
index 0000000..b6f828f
--- /dev/null
+++ b/ViewModels/Dialogs/OpcUaImportDialogViewModel.cs
@@ -0,0 +1,340 @@
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Opc.Ua;
+using Opc.Ua.Client;
+using Opc.Ua.Configuration;
+using PMSWPF.Enums;
+using PMSWPF.Helper;
+using PMSWPF.Models;
+
+namespace PMSWPF.ViewModels.Dialogs;
+
+public partial class OpcUaImportDialogViewModel : ObservableObject
+{
+ [ObservableProperty]
+ private string _endpointUrl = "opc.tcp://127.0.0.1:4855"; // 默认值
+
+ [ObservableProperty]
+ private ObservableCollection _opcUaNodes;
+
+ [ObservableProperty]
+ private ObservableCollection _selectedNodeVariables;
+
+ [ObservableProperty]
+ private bool _selectAllVariables;
+
+ private Session _session;
+
+ public OpcUaImportDialogViewModel()
+ {
+ OpcUaNodes = new ObservableCollection();
+ SelectedNodeVariables = new ObservableCollection();
+ }
+
+ [RelayCommand]
+ private async Task Connect()
+ {
+ try
+ {
+ // 断开现有连接
+ if (_session != null && _session.Connected)
+ {
+ _session.Close();
+ _session.Dispose();
+ _session = null;
+ }
+
+ /*ApplicationInstance application = new ApplicationInstance
+ {
+ ApplicationName = "PMSWPF OPC UA Client",
+ ApplicationType = ApplicationType.Client,
+ ConfigSectionName = "PMSWPF.OpcUaClient"
+ };
+
+ ApplicationConfiguration config = await application.LoadApplicationConfiguration(false);
+
+ // var config = new ApplicationConfiguration()
+ // {
+ // ApplicationName = application.ApplicationName,
+ // ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:OpcUADemoClient",
+ // ApplicationType = application.ApplicationType,
+ // SecurityConfiguration = new SecurityConfiguration
+ // {
+ // ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/MachineDefault", SubjectName = application.ApplicationName },
+ // TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Certificate Authorities" },
+ // TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Applications" },
+ // RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/RejectedCertificates" },
+ // AutoAcceptUntrustedCertificates = true // 自动接受不受信任的证书 (仅用于测试)
+ // },
+ // TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
+ // ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
+ // TraceConfiguration = new TraceConfiguration { OutputFilePath = "./Logs/OpcUaClient.log", DeleteOnLoad = true, TraceMasks = Utils.TraceMasks.Error | Utils.TraceMasks.Security }
+ // };
+ //
+ // bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0);
+ // if (!haveAppCertificate)
+ // {
+ // throw new Exception("Application instance certificate invalid!");
+ // }
+ //
+ // EndpointDescription selectedEndpoint
+ // = CoreClientUtils.SelectEndpoint(application.ApplicationConfiguration, EndpointUrl, false);
+ // EndpointConfiguration endpointConfiguration
+ // = EndpointConfiguration.Create(application.ApplicationConfiguration);
+ // ConfiguredEndpoint configuredEndpoint
+ // = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);
+ // var config = new ApplicationConfiguration()
+ // {
+ // ApplicationName = application.ApplicationName,
+ // ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:OpcUADemoClient",
+ // ApplicationType = application.ApplicationType,
+ // SecurityConfiguration = new SecurityConfiguration
+ // {
+ // ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/MachineDefault", SubjectName = application.ApplicationName },
+ // TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Certificate Authorities" },
+ // TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Applications" },
+ // RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/RejectedCertificates" },
+ // AutoAcceptUntrustedCertificates = true // 自动接受不受信任的证书 (仅用于测试)
+ // },
+ // TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
+ // ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
+ // TraceConfiguration = new TraceConfiguration { OutputFilePath = "./Logs/OpcUaClient.log", DeleteOnLoad = true, TraceMasks = Utils.TraceMasks.Error | Utils.TraceMasks.Security }
+ // };
+
+ bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0);
+ if (!haveAppCertificate)
+ {
+ throw new Exception("Application instance certificate invalid!");
+ }
+
+ EndpointDescription selectedEndpoint
+ = CoreClientUtils.SelectEndpoint(application.ApplicationConfiguration, EndpointUrl, false);
+ EndpointConfiguration endpointConfiguration
+ = EndpointConfiguration.Create(application.ApplicationConfiguration);
+ ConfiguredEndpoint configuredEndpoint
+ = new ConfiguredEndpoint(null, selectedEndpoint, endpointConfiguration);
+
+ _session = await Session.Create(
+ config,
+ configuredEndpoint,
+ false,
+ "PMSWPF OPC UA Session",
+ 60000,
+ new UserIdentity(new AnonymousIdentityToken()),
+ null);
+ */
+
+
+
+ // 1. 创建应用程序配置
+ var application = new ApplicationInstance
+ {
+ ApplicationName = "OpcUADemoClient",
+ ApplicationType = ApplicationType.Client,
+ ConfigSectionName = "Opc.Ua.Client"
+ };
+
+ var config = new ApplicationConfiguration()
+ {
+ ApplicationName = application.ApplicationName,
+ ApplicationUri = $"urn:{System.Net.Dns.GetHostName()}:OpcUADemoClient",
+ ApplicationType = application.ApplicationType,
+ SecurityConfiguration = new SecurityConfiguration
+ {
+ ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/MachineDefault", SubjectName = application.ApplicationName },
+ TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Certificate Authorities" },
+ TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/UA Applications" },
+ RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = "%CommonApplicationData%/OPC Foundation/CertificateStores/RejectedCertificates" },
+ AutoAcceptUntrustedCertificates = true // 自动接受不受信任的证书 (仅用于测试)
+ },
+ TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
+ ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
+ TraceConfiguration = new TraceConfiguration { OutputFilePath = "./Logs/OpcUaClient.log", DeleteOnLoad = true, TraceMasks = Utils.TraceMasks.Error | Utils.TraceMasks.Security }
+ };
+ application.ApplicationConfiguration = config;
+
+ // 验证并检查证书
+ await config.Validate(ApplicationType.Client);
+ await application.CheckApplicationInstanceCertificate(false, 0);
+
+ // 2. 查找并选择端点 (将 useSecurity 设置为 false 以进行诊断)
+ var selectedEndpoint = CoreClientUtils.SelectEndpoint(EndpointUrl, false);
+
+ _session = await Session.Create(
+ config,
+ new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)),
+ false,
+ "PMSWPF OPC UA Session",
+ 60000,
+ new UserIdentity(new AnonymousIdentityToken()),
+ null);
+
+ NotificationHelper.ShowSuccess($"已连接到 OPC UA 服务器: {EndpointUrl}");
+
+ // 浏览根节点
+ await BrowseNodes(OpcUaNodes, ObjectIds.ObjectsFolder);
+ }
+ catch (Exception ex)
+ {
+ NlogHelper.Error($"连接 OPC UA 服务器失败: {EndpointUrl} - {ex.Message}", ex);
+ NotificationHelper.ShowError($"连接 OPC UA 服务器失败: {EndpointUrl} - {ex.Message}", ex);
+ }
+ }
+ ///
+ /// 处理来自服务器的数据变化通知
+ ///
+ private static void OnNotification(MonitoredItem item, MonitoredItemNotificationEventArgs e)
+ {
+ foreach (var value in item.DequeueValues())
+ {
+ Console.WriteLine($"[通知] {item.DisplayName}: {value.Value} | 时间戳: {value.SourceTimestamp.ToLocalTime()} | 状态: {value.StatusCode}");
+ }
+ }
+
+ private async Task BrowseNodes(ObservableCollection nodes, NodeId parentNodeId)
+ {
+ try
+ {
+ Opc.Ua.ReferenceDescriptionCollection references;
+ byte[] continuationPoint = null;
+
+ _session.Browse(
+ null, // RequestHeader
+ new ViewDescription(),
+ parentNodeId,
+ 0u,
+ BrowseDirection.Forward,
+ Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
+ true,
+ (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
+ out continuationPoint,
+ out references
+ );
+
+ foreach (var rd in references)
+ {
+ NodeType nodeType = NodeType.Folder; // 默认是文件夹
+ if ((rd.NodeClass & NodeClass.Variable) != 0)
+ {
+ nodeType = NodeType.Variable;
+ }
+ else if ((rd.NodeClass & NodeClass.Object) != 0)
+ {
+ nodeType = NodeType.Object;
+ }
+
+ var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
+ nodes.Add(opcUaNode);
+
+ // 如果是文件夹或对象,添加一个虚拟子节点,用于懒加载
+ if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
+ {
+ opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ NlogHelper.Error($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
+ NotificationHelper.ShowError($"浏览 OPC UA 节点失败: {parentNodeId} - {ex.Message}", ex);
+ }
+ }
+
+ public async Task LoadNodeVariables(OpcUaNode node)
+ {
+ if (node.NodeType == NodeType.Variable)
+ {
+ // 如果是变量节点,直接显示它
+ SelectedNodeVariables.Clear();
+ SelectedNodeVariables.Add(new VariableData
+ {
+ Name = node.DisplayName,
+ NodeId = node.NodeId.ToString(),
+ OpcUaNodeId = node.NodeId.ToString(),
+ ProtocolType = ProtocolType.OpcUA,
+ IsActive = true // 默认选中
+ });
+ return;
+ }
+
+ if (node.IsLoaded || node.IsLoading)
+ {
+ return; // 已经加载或正在加载
+ }
+
+ node.IsLoading = true;
+ node.Children.Clear(); // 清除虚拟节点
+
+ try
+ {
+ Opc.Ua.ReferenceDescriptionCollection references;
+ byte[] continuationPoint = null;
+
+ _session.Browse(
+ null, // RequestHeader
+ new ViewDescription(),
+ node.NodeId,
+ 0u,
+ BrowseDirection.Forward,
+ Opc.Ua.ReferenceTypeIds.HierarchicalReferences,
+ true,
+ (uint)Opc.Ua.NodeClass.Object | (uint)Opc.Ua.NodeClass.Variable,
+ out continuationPoint,
+ out references
+ );
+
+ foreach (var rd in references)
+ {
+ NodeType nodeType = NodeType.Folder;
+ if ((rd.NodeClass & NodeClass.Variable) != 0)
+ {
+ nodeType = NodeType.Variable;
+ }
+ else if ((rd.NodeClass & NodeClass.Object) != 0)
+ {
+ nodeType = NodeType.Object;
+ }
+
+ var opcUaNode = new OpcUaNode(rd.DisplayName.Text, (NodeId)rd.NodeId, nodeType);
+ node.Children.Add(opcUaNode);
+
+ if (nodeType == NodeType.Folder || nodeType == NodeType.Object)
+ {
+ opcUaNode.Children.Add(new OpcUaNode("Loading...", NodeId.Null, NodeType.Folder)); // 虚拟节点
+ }
+
+ // 如果是变量,添加到右侧列表
+ if (nodeType == NodeType.Variable)
+ {
+ SelectedNodeVariables.Add(new VariableData
+ {
+ Name = opcUaNode.DisplayName,
+ NodeId = opcUaNode.NodeId.ToString(),
+ OpcUaNodeId = opcUaNode.NodeId.ToString(),
+ ProtocolType = ProtocolType.OpcUA,
+ IsActive = true // 默认选中
+ });
+ }
+ }
+
+ node.IsLoaded = true;
+ }
+ catch (Exception ex)
+ {
+ NlogHelper.Error($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
+ NotificationHelper.ShowError($"加载 OPC UA 节点变量失败: {node.NodeId} - {ex.Message}", ex);
+ }
+ finally
+ {
+ node.IsLoading = false;
+ }
+ }
+
+ public ObservableCollection GetSelectedVariables()
+ {
+ return new ObservableCollection(SelectedNodeVariables.Where(v => v.IsActive));
+ }
+}
diff --git a/ViewModels/VariableTableViewModel.cs b/ViewModels/VariableTableViewModel.cs
index 75c0b55..576ce12 100644
--- a/ViewModels/VariableTableViewModel.cs
+++ b/ViewModels/VariableTableViewModel.cs
@@ -44,6 +44,9 @@ partial class VariableTableViewModel : ViewModelBase
[ObservableProperty]
private bool _isS7ProtocolSelected;
+ [ObservableProperty]
+ private bool _isOpcUaProtocolSelected;
+
public VariableTableViewModel(IDialogService dialogService)
{
_dialogService = dialogService;
@@ -85,6 +88,7 @@ partial class VariableTableViewModel : ViewModelBase
public override void OnLoaded()
{
IsS7ProtocolSelected = VariableTable.ProtocolType == ProtocolType.S7;
+ IsOpcUaProtocolSelected = VariableTable.ProtocolType == ProtocolType.OpcUA;
if (VariableTable.DataVariables != null)
{
@@ -223,6 +227,44 @@ partial class VariableTableViewModel : ViewModelBase
}
+ [RelayCommand]
+ private async Task ImportFromOpcUaServer()
+ {
+ try
+ {
+ var importedVariables = await _dialogService.ShowOpcUaImportDialog();
+ if (importedVariables == null || !importedVariables.Any())
+ {
+ return; // 用户取消或没有选择任何变量
+ }
+
+ ContentDialog processingDialog = _dialogService.ShowProcessingDialog("正在处理...", "正在导入OPC UA变量,请稍等片刻....");
+
+ foreach (var variableData in importedVariables)
+ {
+ variableData.CreateTime = DateTime.Now;
+ variableData.VariableTableId = VariableTable.Id;
+ variableData.ProtocolType = ProtocolType.OpcUA; // 确保协议类型正确
+ }
+
+ // 插入数据库
+ var resVarDataCount = await _varDataRepository.AddAsync(importedVariables);
+
+ // 更新界面
+ variableTable.DataVariables = await _varDataRepository.GetAllAsync();
+ _dataVariables = new ObservableCollection(variableTable.DataVariables);
+ processingDialog?.Hide();
+
+ string msgSuccess = $"成功导入OPC UA变量:{resVarDataCount}个。";
+ NlogHelper.Info(msgSuccess);
+ NotificationHelper.ShowSuccess(msgSuccess);
+ }
+ catch (Exception e)
+ {
+ NotificationHelper.ShowError($"从OPC UA服务器导入变量的过程中发生了不可预期的错误:{e.Message}", e);
+ }
+ }
+
[RelayCommand]
private async void AddVarData(VariableTable variableTable)
diff --git a/Views/Dialogs/OpcUaImportDialog.xaml b/Views/Dialogs/OpcUaImportDialog.xaml
new file mode 100644
index 0000000..6269f87
--- /dev/null
+++ b/Views/Dialogs/OpcUaImportDialog.xaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Views/Dialogs/OpcUaImportDialog.xaml.cs b/Views/Dialogs/OpcUaImportDialog.xaml.cs
new file mode 100644
index 0000000..e2a75d2
--- /dev/null
+++ b/Views/Dialogs/OpcUaImportDialog.xaml.cs
@@ -0,0 +1,44 @@
+using System.Windows;
+using CommunityToolkit.Mvvm.Messaging;
+using iNKORE.UI.WPF.Modern.Controls;
+using PMSWPF.Models;
+using PMSWPF.ViewModels.Dialogs;
+
+namespace PMSWPF.Views.Dialogs;
+
+///
+/// OpcUaImportDialog.xaml 的交互逻辑
+///
+public partial class OpcUaImportDialog : ContentDialog
+{
+ public OpcUaImportDialogViewModel ViewModel
+ {
+ get => (OpcUaImportDialogViewModel)DataContext;
+ set => DataContext = value;
+ }
+
+ public OpcUaImportDialog(OpcUaImportDialogViewModel viewModel)
+ {
+ InitializeComponent();
+ ViewModel = viewModel;
+ }
+
+ private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ // 在这里处理导入逻辑,例如获取选中的变量
+ // ViewModel.ImportSelectedVariables();
+ }
+
+ private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ // 处理取消逻辑
+ }
+
+ private async void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs