using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using Prism.Commands; using Prism.Mvvm; using XP.Common.Logging.Interfaces; using XP.Hardware.Plc.Abstractions; using XP.Hardware.Plc.Exceptions; using XP.Hardware.Plc.Services; using XP.Hardware.PLC.Configs; namespace XP.App.ViewModels { /// /// 信号数据服务 DEMO 窗口 ViewModel /// public class SignalDataDemoViewModel : BindableBase { private readonly PlcService _plcService; private readonly ISignalDataService _signalService; private readonly ConfigLoader _configLoader; private readonly ILoggerService _logger; // 日志 public ObservableCollection LogEntries { get; } = new(); // 连接状态 public bool IsConnected => _plcService.IsConnected; public string StatusText => _plcService.StatusText; private bool _isInitialized; public bool IsInitialized { get => _isInitialized; set => SetProperty(ref _isInitialized, value); } // 缓存读取 private string _readSignalName = ""; public string ReadSignalName { get => _readSignalName; set => SetProperty(ref _readSignalName, value); } private string _readResult = ""; public string ReadResult { get => _readResult; set => SetProperty(ref _readResult, value); } // 队列写入 private string _queueSignalName = ""; public string QueueSignalName { get => _queueSignalName; set => SetProperty(ref _queueSignalName, value); } private string _queueWriteValue = ""; public string QueueWriteValue { get => _queueWriteValue; set => SetProperty(ref _queueWriteValue, value); } // 直接写入+回读校验 private string _directSignalName = ""; public string DirectSignalName { get => _directSignalName; set => SetProperty(ref _directSignalName, value); } private string _directWriteValue = ""; public string DirectWriteValue { get => _directWriteValue; set => SetProperty(ref _directWriteValue, value); } // 信号定义文件路径 private string _xmlFilePath = "PlcAddrDfn.xml"; public string XmlFilePath { get => _xmlFilePath; set => SetProperty(ref _xmlFilePath, value); } // 命令 public DelegateCommand ConnectAndLoadCommand { get; } public DelegateCommand CacheReadCommand { get; } public DelegateCommand QueueWriteCommand { get; } public DelegateCommand DirectWriteCommand { get; } public DelegateCommand ClearLogCommand { get; } public SignalDataDemoViewModel( PlcService plcService, ISignalDataService signalService, ConfigLoader configLoader, ILoggerService logger) { _plcService = plcService ?? throw new ArgumentNullException(nameof(plcService)); _signalService = signalService ?? throw new ArgumentNullException(nameof(signalService)); _configLoader = configLoader ?? throw new ArgumentNullException(nameof(configLoader)); _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger)); _plcService.PropertyChanged += (s, e) => { if (e.PropertyName == nameof(PlcService.IsConnected)) RaisePropertyChanged(nameof(IsConnected)); else if (e.PropertyName == nameof(PlcService.StatusText)) RaisePropertyChanged(nameof(StatusText)); }; ConnectAndLoadCommand = new DelegateCommand(async () => await ConnectAndLoadAsync()); CacheReadCommand = new DelegateCommand(CacheRead); QueueWriteCommand = new DelegateCommand(QueueWrite); DirectWriteCommand = new DelegateCommand(async () => await DirectWriteAsync()); ClearLogCommand = new DelegateCommand(() => LogEntries.Clear()); } private void Log(string msg) { var text = $"[{DateTime.Now:HH:mm:ss.fff}] {msg}"; LogEntries.Add(text); } /// /// 连接 PLC 并加载信号定义 /// private async Task ConnectAndLoadAsync() { try { Log("正在加载配置..."); var config = _configLoader.LoadPlcConfig(); Log($"配置加载成功: {config.IpAddress}:{config.Port}, DB读={config.ReadDbBlock}"); Log("正在连接 PLC..."); var result = await _plcService.InitializeAsync(config); if (!result) { Log("ERROR: PLC 连接失败"); return; } Log("PLC 连接成功"); Log($"正在加载信号定义: {XmlFilePath}"); _plcService.LoadSignalDefinitions(XmlFilePath); Log("信号定义加载成功"); IsInitialized = true; } catch (Exception ex) { Log($"ERROR: {ex.Message}"); } } /// /// 缓存读取 /// private void CacheRead() { if (string.IsNullOrWhiteSpace(ReadSignalName)) { Log("ERROR: 请输入信号名称"); return; } try { var value = _signalService.GetValueByName(ReadSignalName); ReadResult = value?.ToString() ?? "null"; Log($"缓存读取成功: {ReadSignalName} = {ReadResult} (类型: {value?.GetType().Name ?? "null"})"); } catch (PlcException ex) { ReadResult = "ERROR"; Log($"ERROR: 缓存读取失败 - {ex.Message}"); } catch (Exception ex) { ReadResult = "ERROR"; Log($"ERROR: {ex.Message}"); } } /// /// 队列写入 /// private void QueueWrite() { if (string.IsNullOrWhiteSpace(QueueSignalName)) { Log("ERROR: 请输入信号名称"); return; } if (string.IsNullOrWhiteSpace(QueueWriteValue)) { Log("ERROR: 请输入写入值"); return; } try { // 尝试解析为数值,否则作为字符串 object value = ParseInputValue(QueueWriteValue); bool enqueued = _signalService.EnqueueWrite(QueueSignalName, value); Log(enqueued ? $"队列写入成功: {QueueSignalName} = {QueueWriteValue}" : $"WARN: 队列写入返回 false(队列未运行或已满): {QueueSignalName}"); } catch (PlcException ex) { Log($"ERROR: 队列写入失败 - {ex.Message}"); } catch (Exception ex) { Log($"ERROR: {ex.Message}"); } } /// /// 直接写入+回读校验 /// private async Task DirectWriteAsync() { if (string.IsNullOrWhiteSpace(DirectSignalName)) { Log("ERROR: 请输入信号名称"); return; } if (string.IsNullOrWhiteSpace(DirectWriteValue)) { Log("ERROR: 请输入写入值"); return; } try { object value = ParseInputValue(DirectWriteValue); Log($"正在直接写入: {DirectSignalName} = {DirectWriteValue}..."); bool verified = await _signalService.WriteDirectWithVerify(DirectSignalName, value); Log(verified ? $"直接写入校验通过: {DirectSignalName} = {DirectWriteValue}" : $"WARN: 直接写入校验失败: {DirectSignalName} = {DirectWriteValue}"); } catch (PlcException ex) { Log($"ERROR: 直接写入失败 - {ex.Message}"); } catch (Exception ex) { Log($"ERROR: {ex.Message}"); } } /// /// 解析用户输入值:尝试 bool → int → double → string /// private object ParseInputValue(string input) { if (bool.TryParse(input, out bool bVal)) return bVal; if (int.TryParse(input, out int iVal)) return iVal; if (double.TryParse(input, out double dVal)) return dVal; return input; } } }