diff --git a/DeviceEditModule/ViewModels/DialogMangerViewModel.cs b/DeviceEditModule/ViewModels/DialogMangerViewModel.cs index 1d29cdd..eab5e53 100644 --- a/DeviceEditModule/ViewModels/DialogMangerViewModel.cs +++ b/DeviceEditModule/ViewModels/DialogMangerViewModel.cs @@ -27,7 +27,7 @@ namespace DeviceEditModule.ViewModels /// 所有 Tab 项集合,绑定到标签条的 ItemsControl。 public ObservableCollection TagItems { get; } = new(); - /// 以 Tab 标题为 key 追踪已打开的 Tab,防止重复打开。 + /// 以设备指纹为 key 追踪已打开的 Tab,防止同一物理设备重复打开。 private readonly Dictionary _tabDictionary = new(); private DialogTabItemVM? _selectedTag; @@ -87,11 +87,11 @@ namespace DeviceEditModule.ViewModels #region Tab 管理 - /// 收到事件:若 Tab 已存在则激活,否则创建并追加到集合。 + /// 收到事件:若指纹已存在则激活,否则创建并追加到集合。 private void OnAddTab(DialogTabInfo info) { - // 已有相同标题的 Tab → 直接激活,不重复创建 - if (_tabDictionary.TryGetValue(info.Title, out var existing)) + // 已有相同指纹的 Tab → 直接激活,不重复创建 + if (!string.IsNullOrEmpty(info.Fingerprint) && _tabDictionary.TryGetValue(info.Fingerprint, out var existing)) { ActivateTab(existing); return; @@ -99,11 +99,14 @@ namespace DeviceEditModule.ViewModels var tab = new DialogTabItemVM(OnSelectTab, OnCloseTab) { - Title = info.Title, - Content = info.Content + Title = info.Title, + Fingerprint = info.Fingerprint, + Content = info.Content }; - _tabDictionary[info.Title] = tab; + if (!string.IsNullOrEmpty(info.Fingerprint)) + _tabDictionary[info.Fingerprint] = tab; + TagItems.Add(tab); RaisePropertyChanged(nameof(HasNoTabs)); ActivateTab(tab); @@ -116,7 +119,8 @@ namespace DeviceEditModule.ViewModels private void OnCloseTab(DialogTabItemVM tab) { int idx = TagItems.IndexOf(tab); - _tabDictionary.Remove(tab.Title); + if (!string.IsNullOrEmpty(tab.Fingerprint)) + _tabDictionary.Remove(tab.Fingerprint); TagItems.Remove(tab); RaisePropertyChanged(nameof(HasNoTabs)); diff --git a/TestingModule/ViewModels/ParametersManagerViewModel.cs b/TestingModule/ViewModels/ParametersManagerViewModel.cs index f5cf47a..7f7f61d 100644 --- a/TestingModule/ViewModels/ParametersManagerViewModel.cs +++ b/TestingModule/ViewModels/ParametersManagerViewModel.cs @@ -147,11 +147,14 @@ namespace TestingModule.ViewModels } // 4. 发布事件 → DialogMangerViewModel 接收后将此 View 添加为 Tab - // 标题格式:{当前作用域} - {设备名称},作为全局唯一 Tab 标识 + // 标题格式:{当前作用域} - {设备名称} + // 去重依据:设备硬件指纹(同一物理设备不重复打开) + var fingerprint = DeviceManager.ExtractHardwareFingerprint(SelectedDevice); _eventAggregator.GetEvent().Publish(new DialogTabInfo { - Title = $"{_globalInfo.CurrentScope} - {SelectedDevice.DeviceName}", - Content = view + Title = $"{_globalInfo.CurrentScope} - {SelectedDevice.DeviceName}", + Fingerprint = fingerprint, + Content = view }); // 5. 将窗口置顶(确保用户看到新增的 Tab) diff --git a/UIShare/GlobalVariable/DeviceManager.cs b/UIShare/GlobalVariable/DeviceManager.cs index 3202aa8..2a9fa7e 100644 --- a/UIShare/GlobalVariable/DeviceManager.cs +++ b/UIShare/GlobalVariable/DeviceManager.cs @@ -38,7 +38,7 @@ namespace UIShare.GlobalVariable /// 根据设备配置提取唯一的硬件指纹字符串。 /// Tcp → "Tcp:IP:Port";Serial → "Serial:PortName";无法识别则返回空字符串。 /// - private static string ExtractHardwareFingerprint(DeviceInfoVM config) + public static string ExtractHardwareFingerprint(DeviceInfoVM config) { if (string.Equals(config.ConnectionType, "Tcp", StringComparison.OrdinalIgnoreCase) && config.TcpConfig != null) diff --git a/UIShare/UIViewModel/DialogTabInfo.cs b/UIShare/UIViewModel/DialogTabInfo.cs index d8b5e5b..1ef06b4 100644 --- a/UIShare/UIViewModel/DialogTabInfo.cs +++ b/UIShare/UIViewModel/DialogTabInfo.cs @@ -10,6 +10,12 @@ namespace UIShare.UIViewModel /// Tab 标题(显示在标签页上)。 public string Title { get; set; } = string.Empty; + /// + /// 设备硬件指纹(如 "Tcp:192.168.1.100:502"),用于去重判断, + /// 防止同一物理设备被重复打开多个 Tab。 + /// + public string Fingerprint { get; set; } = string.Empty; + /// /// Tab 内容:传入一个已实例化的 (通常是 UserControl), /// 由 ContentControl 直接承载展示。 diff --git a/UIShare/UIViewModel/DialogTabItemVM.cs b/UIShare/UIViewModel/DialogTabItemVM.cs index ff86357..b09fc32 100644 --- a/UIShare/UIViewModel/DialogTabItemVM.cs +++ b/UIShare/UIViewModel/DialogTabItemVM.cs @@ -21,6 +21,14 @@ namespace DeviceEditModule.ViewModels set => SetProperty(ref _title, value); } + private string _fingerprint = string.Empty; + /// 设备硬件指纹,用于去重字典的 Key。 + public string Fingerprint + { + get => _fingerprint; + set => SetProperty(ref _fingerprint, value); + } + private object? _content; /// Tab 内容区域(通常为 UserControl 实例)。 public object? Content