Files
ADP/DeviceEditModule/ViewModels/DialogMangerViewModel.cs
T
2026-06-23 10:50:43 +08:00

154 lines
5.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Prism.Commands;
using Prism.Ioc;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Input;
using UIShare.PubEvent;
using UIShare.UIViewModel;
using UIShare.ViewModelBase;
namespace DeviceEditModule.ViewModels
{
/// <summary>
/// 弹窗管理器 ViewModel。
/// <para>
/// 职责:<br/>
/// 1. 订阅 <see cref="AddDialogTabEvent"/>,将外部弹窗注册为 Tab<br/>
/// 2. 维护 <see cref="TagItems"/> 集合,控制选中/关闭逻辑;<br/>
/// 3. 最小化:通过 <see cref="MinimizeRequested"/> 事件通知 View 执行 P/Invoke 窗口操作;<br/>
/// 4. 关闭:调用 <see cref="RequestClose"/>。
/// </para>
/// </summary>
public class DialogMangerViewModel : DialogViewModelBase, IDisposable
{
#region 属性
/// <summary>所有 Tab 项集合,绑定到标签条的 ItemsControl。</summary>
public ObservableCollection<DialogTabItemVM> TagItems { get; } = new();
/// <summary>以设备指纹为 key 追踪已打开的 Tab,防止同一物理设备重复打开。</summary>
private readonly Dictionary<string, DialogTabItemVM> _tabDictionary = new();
private DialogTabItemVM? _selectedTag;
/// <summary>当前激活的 Tab,其 Content 显示在内容区。</summary>
public DialogTabItemVM? SelectedTag
{
get => _selectedTag;
set => SetProperty(ref _selectedTag, value);
}
/// <summary>是否没有任何 Tab(用于绑定空状态提示的 Visibility)。</summary>
public bool HasNoTabs => TagItems.Count == 0;
#endregion
#region 命令
public ICommand MinimizeCommand { get; }
public ICommand CloseCommand { get; }
#endregion
#region 事件
/// <summary>
/// View 订阅此事件后,在事件回调里执行 P/Invoke 最小化。
/// 这样 ViewModel 无需引用任何 UI 或 Win32 类型。
/// </summary>
public event EventHandler? MinimizeRequested;
public event EventHandler? RestoreRequested;
#endregion
public DialogMangerViewModel(IContainerProvider containerProvider) : base(containerProvider)
{
MinimizeCommand = new DelegateCommand(OnMinimize);
CloseCommand = new DelegateCommand(OnClose);
// 订阅来自其他模块的"添加 Tab"事件
_eventAggregator.GetEvent<AddDialogTabEvent>().Subscribe(OnAddTab, ThreadOption.UIThread);
_eventAggregator.GetEvent<CancelMinimizeEvent>().Subscribe(()=>RestoreRequested.Invoke(this, EventArgs.Empty));
}
#region 命令处理
private void OnMinimize() => MinimizeRequested?.Invoke(this, EventArgs.Empty);
private void OnClose()
{
// 关闭前清空所有 Tab,释放内容引用,并清除去重字典
_tabDictionary.Clear();
TagItems.Clear();
SelectedTag = null;
RequestClose.Invoke();
}
#endregion
#region Tab 管理
/// <summary>收到事件:若指纹已存在则激活,否则创建并追加到集合。</summary>
private void OnAddTab(DialogTabInfo info)
{
// 已有相同指纹的 Tab → 直接激活,不重复创建
if (!string.IsNullOrEmpty(info.Fingerprint) && _tabDictionary.TryGetValue(info.Fingerprint, out var existing))
{
ActivateTab(existing);
return;
}
var tab = new DialogTabItemVM(OnSelectTab, OnCloseTab)
{
Title = info.Title,
Fingerprint = info.Fingerprint,
Content = info.Content
};
if (!string.IsNullOrEmpty(info.Fingerprint))
_tabDictionary[info.Fingerprint] = tab;
TagItems.Add(tab);
RaisePropertyChanged(nameof(HasNoTabs));
ActivateTab(tab);
}
/// <summary>激活(选中)指定 Tab,其余全部取消选中。</summary>
private void OnSelectTab(DialogTabItemVM tab) => ActivateTab(tab);
/// <summary>关闭指定 Tab,自动选中相邻 Tab(或清空内容区)。</summary>
private void OnCloseTab(DialogTabItemVM tab)
{
int idx = TagItems.IndexOf(tab);
if (!string.IsNullOrEmpty(tab.Fingerprint))
_tabDictionary.Remove(tab.Fingerprint);
TagItems.Remove(tab);
RaisePropertyChanged(nameof(HasNoTabs));
if (TagItems.Count == 0)
{
SelectedTag = null;
return;
}
// 优先选左侧邻 Tab,无左侧则选当前索引(已向左移一位)
ActivateTab(TagItems[Math.Max(0, idx - 1)]);
}
private void ActivateTab(DialogTabItemVM tab)
{
foreach (var t in TagItems)
t.IsSelected = false;
tab.IsSelected = true;
SelectedTag = tab;
}
#endregion
public void Dispose()
{
_eventAggregator.GetEvent<AddDialogTabEvent>().Unsubscribe(OnAddTab);
}
}
}