using log4net; using Plugin.DeviceDebug.Entity; using System; using System.Windows; using System.Windows.Controls; namespace Plugin.DeviceDebug.Panels { /// /// CAN 调试面板多通道壳:以 TabControl 承载若干 , /// 支持同屏并列多个 CAN 通道独立收发(验收场景 4)。 /// 对外保持与旧单面板一致的属性契约(DeviceId/InitialBusName/InitialNodeIndex/ /// AutoConnectOnLoad/ExistingDriver/IsMaintenanceMode/OnCommandExecute), /// DeviceDebug 选设备时这些配置被转发到"设备通道"(首个 Tab)。 /// public partial class CanDebugPanel : UserControl { private static readonly ILog log = LogManager.GetLogger(typeof(CanDebugPanel)); public static readonly DependencyProperty IsMaintenanceModeProperty = DependencyProperty.Register(nameof(IsMaintenanceMode), typeof(bool), typeof(CanDebugPanel), new PropertyMetadata(false, OnMaintenanceModeChanged)); public bool IsMaintenanceMode { get => (bool)GetValue(IsMaintenanceModeProperty); set => SetValue(IsMaintenanceModeProperty, value); } private static void OnMaintenanceModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var panel = (CanDebugPanel)d; if (panel._deviceChannel != null) panel._deviceChannel.IsMaintenanceMode = (bool)e.NewValue; } /// 命令执行事件(任一通道触发均上抛,供 DeviceDebug 统一处理) public event EventHandler? OnCommandExecute; private CanChannelView? _deviceChannel; private int _manualSeq; // 待转发到设备通道的配置(可能早于通道创建) private string _deviceId = string.Empty; private string _initialBusName; private int? _initialNodeIndex; private bool _autoConnectOnLoad; private Aging.Infrastructure.Contracts.IDeviceDriver? _existingDriver; public CanDebugPanel() { InitializeComponent(); } /// 设备ID(转发到设备通道) public string DeviceId { get => _deviceId; set { _deviceId = value; EnsureDeviceChannel().DeviceId = value; } } /// 总线名称(转发到设备通道) public string InitialBusName { get => _initialBusName; set { _initialBusName = value; EnsureDeviceChannel().InitialBusName = value; } } /// 节点编号(转发到设备通道) public int? InitialNodeIndex { get => _initialNodeIndex; set { _initialNodeIndex = value; EnsureDeviceChannel().InitialNodeIndex = value; } } /// 加载即自动连接(转发到设备通道) public bool AutoConnectOnLoad { get => _autoConnectOnLoad; set { _autoConnectOnLoad = value; EnsureDeviceChannel().AutoConnectOnLoad = value; } } /// 外部已注册驱动(转发到设备通道,共享设备复用宿主通路) public Aging.Infrastructure.Contracts.IDeviceDriver? ExistingDriver { get => _existingDriver; set { _existingDriver = value; EnsureDeviceChannel().ExistingDriver = value; } } /// 惰性创建"设备通道"(首个 Tab),并挂接命令事件与当前维护态。 private CanChannelView EnsureDeviceChannel() { if (_deviceChannel != null) return _deviceChannel; _deviceChannel = new CanChannelView(); WireChannel(_deviceChannel, MakeHeader(_deviceId, _initialBusName, _initialNodeIndex)); // 应用已到达的维护态 _deviceChannel.IsMaintenanceMode = IsMaintenanceMode; var devTab = MakeTab(_deviceChannel); devTab.Header = MakeHeader(_deviceId, _initialBusName, _initialNodeIndex); channelTabs.Items.Add(devTab); return _deviceChannel; } private void WireChannel(CanChannelView view, string header) { view.OnCommandExecute += (s, e) => OnCommandExecute?.Invoke(this, e); } private TabItem MakeTab(CanChannelView view) { // 复用视图自身的标题区不显示设备名,这里用 Tab 头标注通道身份 return new TabItem { Content = view }; } private static string MakeHeader(string deviceId, string bus, int? node) { string id = string.IsNullOrEmpty(deviceId) ? "通道" : deviceId; if (!string.IsNullOrEmpty(bus)) return $"{id} @{bus}:{node}"; return id; } /// 手动添加一个可编辑的空白通道(Local TCP 直连,用户自填总线/节点后连接)。 private void AddChannelBtn_Click(object sender, RoutedEventArgs e) { var view = new CanChannelView { AutoConnectOnLoad = false }; _manualSeq++; string header = $"CAN 通道 #{_manualSeq}"; // 手动通道具体总线/节点由用户页内填写,标签不预设 WireChannel(view, header); var tab = MakeTab(view); tab.Header = header; channelTabs.Items.Add(tab); channelTabs.SelectedItem = tab; log.Info($"[CanDebugPanel] 手动添加通道 {header}"); } /// 关闭当前选中的通道(设备通道不可关闭,避免误退出 DeviceDebug 会话视图)。 private void CloseChannelBtn_Click(object sender, RoutedEventArgs e) { if (channelTabs.SelectedItem is not TabItem tab) return; if (tab.Content == _deviceChannel) { MessageBox.Show("设备通道不可在此关闭,请从设备选择切换。", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; } if (tab.Content is CanChannelView view) view.DisconnectInternalSafe(); channelTabs.Items.Remove(tab); } /// 更新设备通道 Tab 头(在配置齐备后调用一次即可)。 public void RefreshDeviceHeader() { if (_deviceChannel == null || channelTabs.Items.Count == 0) return; if (channelTabs.Items[0] is TabItem t) t.Header = MakeHeader(_deviceId, _initialBusName, _initialNodeIndex); } } }