diff --git a/CANModule/ViewModels/ZLGCANFDViewModel.cs b/CANModule/ViewModels/ZLGCANFDViewModel.cs index ebc426d..814ab95 100644 --- a/CANModule/ViewModels/ZLGCANFDViewModel.cs +++ b/CANModule/ViewModels/ZLGCANFDViewModel.cs @@ -636,11 +636,14 @@ namespace CANModule.ViewModels { // 提取实际 CAN ID(去掉扩展帧标志位) int actualId = (int)(canId & 0x1FFFFFFF); + // 原始字节转为 [0x00, 0x01, ...] 格式,供监视表格直接显示 + string hexData = 十六进制字符串转换(data); var find = CanMessageList.FirstOrDefault(s => s.报文ID == actualId && s.通道 == channel); if (find != null) { find.时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(); find.长度 = dlcLength; + find.数据 = hexData; } else { @@ -649,7 +652,8 @@ namespace CANModule.ViewModels 通道 = (byte)channel, 报文ID = actualId, 时间戳 = (ulong)DateTimeOffset.Now.ToUnixTimeMilliseconds(), - 长度 = dlcLength + 长度 = dlcLength, + 数据 = hexData }); } }); diff --git a/CANModule/Views/ZLGCANFDView.xaml b/CANModule/Views/ZLGCANFDView.xaml index b063f7c..ac149cb 100644 --- a/CANModule/Views/ZLGCANFDView.xaml +++ b/CANModule/Views/ZLGCANFDView.xaml @@ -79,16 +79,17 @@ - - - + + + + diff --git a/UIShare/UIViewModel/CanMessageShowVM.cs b/UIShare/UIViewModel/CanMessageShowVM.cs index d406b6c..0bdb89a 100644 --- a/UIShare/UIViewModel/CanMessageShowVM.cs +++ b/UIShare/UIViewModel/CanMessageShowVM.cs @@ -7,6 +7,7 @@ private int _报文ID; private double _时间戳; private byte _长度; + private string _数据; // 通道属性 @@ -37,6 +38,13 @@ set { SetProperty(ref _长度, value); } } + // 数据属性(原始报文字节十六进制字符串,如 [0x00, 0x01, ...]) + public string 数据 + { + get { return _数据; } + set { SetProperty(ref _数据, value); } + } + } } diff --git a/gen_device_views.ps1 b/gen_device_views.ps1 new file mode 100644 index 0000000..5a8f937 --- /dev/null +++ b/gen_device_views.ps1 @@ -0,0 +1,671 @@ +$ErrorActionPreference = "Stop" + +# ============================================================ +# 通用模板函数 +# ============================================================ + +function Write-ViewModel { + param( + [string]$ProjectPath, # e.g. "c:\Users\kk\Desktop\BOB" + [string]$ClassName, # e.g. "E36233A" + [string]$DeviceType, # e.g. "可编程直流电源" + [string]$DeviceNamespace, # e.g. "DeviceCommand.Device" + [string]$Properties, # C# property block + [string]$Commands, # ICommand declarations + [string]$CommandInits, # Command initialization in constructor + [string]$ExtraUsings = "" + ) + + $dir = Join-Path $ProjectPath "DeviceEditModule\ViewModels" + if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + + $content = @" +using $DeviceNamespace; +using Prism.Commands; +using Prism.Ioc; +using System; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Input; +using UIShare.GlobalVariable; +using UIShare.ViewModelBase; +$ExtraUsings + +namespace DeviceEditModule.ViewModels +{ + /// + /// $ClassName $DeviceType 控制面板 ViewModel + /// + public class ${ClassName}ViewModel : NavigateViewModelBase, IDisposable + { + #region 私有字段 + + private readonly DeviceManager _deviceManager; + private ${ClassName}? _device; + private CancellationTokenSource? _cts; + + #endregion + + #region 设备信息属性 + + private string _deviceName = "$ClassName"; + public string DeviceName + { + get => _deviceName; + set => SetProperty(ref _deviceName, value); + } + + private bool _isConnected; + public bool IsConnected + { + get => _isConnected; + set => SetProperty(ref _isConnected, value); + } + + private bool _isBusy; + /// 正在执行设备命令时为 true,用于 UI 忙碌状态指示。 + public bool IsBusy + { + get => _isBusy; + set => SetProperty(ref _isBusy, value); + } + + #endregion + +$Properties + + private string _responseLog = string.Empty; + /// 命令响应日志(最新消息在顶部)。 + public string ResponseLog + { + get => _responseLog; + set => SetProperty(ref _responseLog, value); + } + + #endregion + + #region 命令 + +$Commands + + #endregion + + public ${ClassName}ViewModel(IContainerProvider containerProvider) : base(containerProvider) + { + _deviceManager = containerProvider.Resolve(); + +$CommandInits + + Initialize(); + } + + #region 初始化 / Navigation + + public void Initialize(string? deviceName = null) + { + ${ClassName}? found = null; + string? foundName = null; + + if (deviceName != null && + _deviceManager.DeviceMap.TryGetValue(deviceName, out var d) && + d is ${ClassName} e) + { + found = e; + foundName = deviceName; + } + else + { + foreach (var kv in _deviceManager.DeviceMap) + { + if (kv.Value is ${ClassName} it) + { + found = it; + foundName = kv.Key; + break; + } + } + } + + _device = found; + DeviceName = foundName ?? "$ClassName (未找到)"; + IsConnected = _device?.IsConnected ?? false; + + AppendLog(found != null + ? $"已关联设备 [{DeviceName}],连接状态:{(IsConnected ? "已连接" : "未连接")}" + : "未在 DeviceManager 中找到 $ClassName 设备,请先初始化设备配置。"); + } + + public override void OnNavigatedTo(NavigationContext context) + { + var name = context.Parameters.GetValue("DeviceName"); + Initialize(name); + } + + #endregion + + #region 辅助 + + private CancellationToken Ct() => (_cts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token; + + private async Task Exec(Func action) + { + if (_device == null) + { + AppendLog("错误:未关联到设备实例,请检查设备配置。"); + return; + } + if (IsBusy) return; + IsBusy = true; + try + { + await action(); + IsConnected = _device.IsConnected; + } + catch (OperationCanceledException) + { + AppendLog("命令超时或已取消。"); + } + catch (Exception ex) + { + AppendLog($"错误:{ex.Message}"); + } + finally + { + IsBusy = false; + } + } + + private void AppendLog(string message) + { + var line = $"[{DateTime.Now:HH:mm:ss}] {message}"; + ResponseLog = ResponseLog.Length > 4000 + ? line + "\n" + ResponseLog[..3000] + : line + "\n" + ResponseLog; + } + + #endregion + + public void Dispose() + { + _cts?.Cancel(); + _cts?.Dispose(); + } + } +} +"@ + $file = Join-Path $dir "${ClassName}ViewModel.cs" + [System.IO.File]::WriteAllText($file, $content, [System.Text.Encoding]::UTF8) + Write-Host " Created: $file" +} + +function Write-ViewXaml { + param( + [string]$ProjectPath, + [string]$ClassName, + [string]$DeviceTitle, # e.g. "E36233A 可编程直流电源" + [string]$Icon, # e.g. "Flash" + [string]$LeftGroups, # GroupBox XAML blocks for left column + [string]$RightGroups # GroupBox XAML blocks for right column + ) + + $dir = Join-Path $ProjectPath "DeviceEditModule\Views" + if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + + $content = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +$LeftGroups + + + + +$RightGroups + + + + + +"@ + $file = Join-Path $dir "${ClassName}View.xaml" + [System.IO.File]::WriteAllText($file, $content, [System.Text.Encoding]::UTF8) + Write-Host " Created: $file" +} + +function Write-ViewXamlCs { + param( + [string]$ProjectPath, + [string]$ClassName + ) + + $dir = Join-Path $ProjectPath "DeviceEditModule\Views" + $content = @" +using System.Windows.Controls; + +namespace DeviceEditModule.Views +{ + /// + /// ${ClassName}View.xaml 的交互逻辑 + /// + public partial class ${ClassName}View : UserControl + { + public ${ClassName}View() + { + InitializeComponent(); + } + } +} +"@ + $file = Join-Path $dir "${ClassName}View.xaml.cs" + [System.IO.File]::WriteAllText($file, $content, [System.Text.Encoding]::UTF8) + Write-Host " Created: $file" +} + +# ============================================================ +# XAML 通用片段 +# ============================================================ + +$XamlLogGroup = @" + + + +