using log4net;
|
using Plugin.DeviceDebug.Entity;
|
using System;
|
using System.Windows;
|
using System.Windows.Controls;
|
|
namespace Plugin.DeviceDebug.Panels
|
{
|
/// <summary>
|
/// CAN 调试面板多通道壳:以 TabControl 承载若干 <see cref="CanChannelView"/>,
|
/// 支持同屏并列多个 CAN 通道独立收发(验收场景 4)。
|
/// 对外保持与旧单面板一致的属性契约(DeviceId/InitialBusName/InitialNodeIndex/
|
/// AutoConnectOnLoad/ExistingDriver/IsMaintenanceMode/OnCommandExecute),
|
/// DeviceDebug 选设备时这些配置被转发到"设备通道"(首个 Tab)。
|
/// </summary>
|
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;
|
}
|
|
/// <summary>命令执行事件(任一通道触发均上抛,供 DeviceDebug 统一处理)</summary>
|
public event EventHandler<DebugCommand>? 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();
|
}
|
|
/// <summary>设备ID(转发到设备通道)</summary>
|
public string DeviceId
|
{
|
get => _deviceId;
|
set { _deviceId = value; EnsureDeviceChannel().DeviceId = value; }
|
}
|
|
/// <summary>总线名称(转发到设备通道)</summary>
|
public string InitialBusName
|
{
|
get => _initialBusName;
|
set { _initialBusName = value; EnsureDeviceChannel().InitialBusName = value; }
|
}
|
|
/// <summary>节点编号(转发到设备通道)</summary>
|
public int? InitialNodeIndex
|
{
|
get => _initialNodeIndex;
|
set { _initialNodeIndex = value; EnsureDeviceChannel().InitialNodeIndex = value; }
|
}
|
|
/// <summary>加载即自动连接(转发到设备通道)</summary>
|
public bool AutoConnectOnLoad
|
{
|
get => _autoConnectOnLoad;
|
set { _autoConnectOnLoad = value; EnsureDeviceChannel().AutoConnectOnLoad = value; }
|
}
|
|
/// <summary>外部已注册驱动(转发到设备通道,共享设备复用宿主通路)</summary>
|
public Aging.Infrastructure.Contracts.IDeviceDriver? ExistingDriver
|
{
|
get => _existingDriver;
|
set { _existingDriver = value; EnsureDeviceChannel().ExistingDriver = value; }
|
}
|
|
/// <summary>惰性创建"设备通道"(首个 Tab),并挂接命令事件与当前维护态。</summary>
|
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;
|
}
|
|
/// <summary>手动添加一个可编辑的空白通道(Local TCP 直连,用户自填总线/节点后连接)。</summary>
|
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}");
|
}
|
|
/// <summary>关闭当前选中的通道(设备通道不可关闭,避免误退出 DeviceDebug 会话视图)。</summary>
|
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);
|
}
|
|
/// <summary>更新设备通道 Tab 头(在配置齐备后调用一次即可)。</summary>
|
public void RefreshDeviceHeader()
|
{
|
if (_deviceChannel == null || channelTabs.Items.Count == 0) return;
|
if (channelTabs.Items[0] is TabItem t)
|
t.Header = MakeHeader(_deviceId, _initialBusName, _initialNodeIndex);
|
}
|
}
|
}
|