using Microsoft.Extensions.Logging; using MyAvaloniaApp.Services; using MyAvaloniaApp.ViewModels.Base; using MyAvaloniaApp.ViewModels.Pages; using ReactiveUI; using System; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Linq; namespace MyAvaloniaApp.ViewModels; /// /// 主窗口的 ViewModel,使用完整的 ReactiveUI 路由系统 /// public class MainWindowViewModel : ReactiveObject { private string _title = "My Avalonia App - ReactiveUI 路由"; private string _headerTitle = "系统管理平台"; private string _headerSubtitle = "欢迎使用现代化管理界面"; private ObservableCollection _navigationItems = new(); private ObservableCollection _tabs = new(); private NavigationItem? _selectedNavigationItem; private TabItem? _selectedTab; private readonly ILogger? _logger; private readonly IDataService? _dataService; private readonly IResourceService? _resourceService; private readonly IScreen _screen; public string Title { get => _title; set => this.RaiseAndSetIfChanged(ref _title, value); } public string HeaderTitle { get => _headerTitle; set => this.RaiseAndSetIfChanged(ref _headerTitle, value); } public string HeaderSubtitle { get => _headerSubtitle; set => this.RaiseAndSetIfChanged(ref _headerSubtitle, value); } public ObservableCollection NavigationItems { get => _navigationItems; set => this.RaiseAndSetIfChanged(ref _navigationItems, value); } public ObservableCollection Tabs { get => _tabs; set => this.RaiseAndSetIfChanged(ref _tabs, value); } public NavigationItem? SelectedNavigationItem { get => _selectedNavigationItem; set => this.RaiseAndSetIfChanged(ref _selectedNavigationItem, value); } public TabItem? SelectedTab { get => _selectedTab; set => this.RaiseAndSetIfChanged(ref _selectedTab, value); } /// /// 路由状态(暴露给 UI 使用) /// public RoutingState Router => _screen.Router; // 响应式命令 public ReactiveCommand NavigateCommand { get; } public ReactiveCommand CloseTabCommand { get; } public ReactiveCommand SelectTabCommand { get; } public MainWindowViewModel(IScreen screen, ILogger? logger = null, IDataService? dataService = null, IResourceService? resourceService = null) { _screen = screen; _logger = logger; _dataService = dataService; _resourceService = resourceService; _logger?.LogInformation("MainWindowViewModel 已创建"); // 初始化导航项(需要在订阅 Router 之前) InitializeNavigationItems(); // 创建导航命令 NavigateCommand = ReactiveCommand.Create(NavigateToPage); // 创建关闭标签页命令 CloseTabCommand = ReactiveCommand.Create(CloseTab); // 创建选择标签页命令 SelectTabCommand = ReactiveCommand.Create(SelectTab); // 监听导航项选择变化 // 注意:这些订阅会在 ViewModel 的整个生命周期内保持活跃 // 由于 MainWindowViewModel 是单例或长生命周期对象,这是可以接受的 // 如果需要更精细的订阅管理,可以在 View 的 WhenActivated 中使用 this.WhenAnyValue(x => x.SelectedNavigationItem) .Where(item => item != null) .Subscribe(item => _logger?.LogInformation("导航到: {Title}", item!.Title)); // 监听标签页选择变化 this.WhenAnyValue(x => x.SelectedTab) .Where(tab => tab != null) .Subscribe(tab => _logger?.LogInformation("切换到标签页: {Title}", tab!.Title)); // 监听 Router.CurrentViewModel 变化,同步标签页 // 这个订阅对于路由系统正常工作至关重要,必须保持活跃 _screen.Router .CurrentViewModel .Subscribe(viewModel => { OnRouterViewModelChanged(viewModel); }); } private void InitializeNavigationItems() { _navigationItems = new ObservableCollection { new NavigationItem { Id = "dashboard", Title = _resourceService?.GetString("NavDashboard") ?? "仪表板", IconType = HeroIconsAvalonia.Enums.IconType.Home, ViewModel = new DashboardPageViewModel(_screen) }, new NavigationItem { Id = "users", Title = _resourceService?.GetString("NavUsers") ?? "用户管理", IconType = HeroIconsAvalonia.Enums.IconType.Users, Children = new ObservableCollection { new NavigationItem { Id = "users-list", Title = "用户列表", IconType = HeroIconsAvalonia.Enums.IconType.UserGroup, ViewModel = new UsersPageViewModel(_screen) }, new NavigationItem { Id = "users-roles", Title = "角色管理", IconType = HeroIconsAvalonia.Enums.IconType.ShieldCheck, ViewModel = new UsersPageViewModel(_screen) }, new NavigationItem { Id = "users-permissions", Title = "权限设置", IconType = HeroIconsAvalonia.Enums.IconType.Key, ViewModel = new UsersPageViewModel(_screen) } } }, new NavigationItem { Id = "settings", Title = _resourceService?.GetString("NavSettings") ?? "系统设置", IconType = HeroIconsAvalonia.Enums.IconType.Cog6Tooth, Children = new ObservableCollection { new NavigationItem { Id = "settings-general", Title = "常规设置", IconType = HeroIconsAvalonia.Enums.IconType.Cog, ViewModel = new SettingsPageViewModel(_screen) }, new NavigationItem { Id = "settings-security", Title = "安全设置", IconType = HeroIconsAvalonia.Enums.IconType.LockClosed, ViewModel = new SettingsPageViewModel(_screen) }, new NavigationItem { Id = "settings-backup", Title = "备份恢复", IconType = HeroIconsAvalonia.Enums.IconType.CloudArrowUp, ViewModel = new SettingsPageViewModel(_screen) } } }, new NavigationItem { Id = "reports", Title = _resourceService?.GetString("NavReports") ?? "报表统计", IconType = HeroIconsAvalonia.Enums.IconType.ChartBar, ViewModel = new ReportsPageViewModel(_screen) }, new NavigationItem { Id = "help", Title = _resourceService?.GetString("NavHelp") ?? "帮助中心", IconType = HeroIconsAvalonia.Enums.IconType.QuestionMarkCircle, ViewModel = new HelpPageViewModel(_screen) }, new NavigationItem { Id = "dialog-host", Title = "对话框示例", IconType = HeroIconsAvalonia.Enums.IconType.ChatBubbleLeftRight, ViewModel = new DialogHostPageViewModel(_screen) }, new NavigationItem { Id = "icons", Title = _resourceService?.GetString("NavIcons") ?? "图标库", IconType = HeroIconsAvalonia.Enums.IconType.Sparkles, ViewModel = new IconsPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger) }, new NavigationItem { Id = "editor", Title = "代码编辑器", IconType = HeroIconsAvalonia.Enums.IconType.CodeBracket, ViewModel = new EditorPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger) } }; // 默认选中第一个导航项并导航 if (_navigationItems.Count > 0 && _navigationItems[0].ViewModel != null) { _navigationItems[0].IsSelected = true; SelectedNavigationItem = _navigationItems[0]; // 初始导航到仪表板 var initialViewModel = _navigationItems[0].ViewModel; if (initialViewModel != null) { _screen.Router.Navigate.Execute(initialViewModel); } } } private void NavigateToPage(NavigationItem navigationItem) { if (navigationItem == null) return; // 检查是否是子级菜单项 bool isChildItem = _navigationItems.Any(parent => parent.Children.Contains(navigationItem)); if (isChildItem) { // 子级菜单项:处理导航 if (navigationItem.ViewModel == null) return; // 取消所有导航项的选中状态 foreach (var item in _navigationItems) { item.IsSelected = false; foreach (var child in item.Children) { child.IsSelected = false; } } // 设置当前子项为选中状态 navigationItem.IsSelected = true; SelectedNavigationItem = navigationItem; // 使用 ReactiveUI 路由导航 _screen.Router.Navigate.Execute(navigationItem.ViewModel); _logger?.LogInformation("导航到子页面: {Title}", navigationItem.Title); } else if (navigationItem.HasChildren) { // 父级菜单项:处理展开/收起逻辑 if (navigationItem.IsExpanded) { // 如果已经展开,则收起 navigationItem.IsExpanded = false; // 取消所有导航项的选中状态 foreach (var item in _navigationItems) { item.IsSelected = false; foreach (var child in item.Children) { child.IsSelected = false; } } SelectedNavigationItem = null; _logger?.LogInformation("收起导航项: {Title}", navigationItem.Title); } else { // 如果未展开,则展开并选中第一个子项 foreach (var item in _navigationItems) { if (item != navigationItem && item.HasChildren) { item.IsExpanded = false; item.IsSelected = false; foreach (var child in item.Children) { child.IsSelected = false; } } } navigationItem.IsExpanded = true; // 选中第一个子项并导航 if (navigationItem.Children.Count > 0) { var firstChild = navigationItem.Children[0]; firstChild.IsSelected = true; SelectedNavigationItem = firstChild; if (firstChild.ViewModel != null) { _screen.Router.Navigate.Execute(firstChild.ViewModel); } } _logger?.LogInformation("展开导航项: {Title}", navigationItem.Title); } } else { // 无子项的父级导航项,直接选中并导航 foreach (var item in _navigationItems) { if (item.HasChildren) { item.IsExpanded = false; } item.IsSelected = false; foreach (var child in item.Children) { child.IsSelected = false; } } navigationItem.IsSelected = true; SelectedNavigationItem = navigationItem; // 使用 ReactiveUI 路由导航 if (navigationItem.ViewModel != null) { _screen.Router.Navigate.Execute(navigationItem.ViewModel); } _logger?.LogInformation("导航到页面: {Title}", navigationItem.Title); } } /// /// Router.CurrentViewModel 变化时的处理 /// private void OnRouterViewModelChanged(IRoutableViewModel? viewModel) { if (viewModel == null) return; // 查找对应的导航项 var navigationItem = FindNavigationItemByViewModel(viewModel); if (navigationItem == null) return; // 创建或更新标签页 var existingTab = _tabs.FirstOrDefault(t => t.Id == navigationItem.Id); if (existingTab != null) { foreach (var tab in _tabs) { tab.IsSelected = false; } existingTab.IsSelected = true; SelectedTab = existingTab; } else { var newTab = new TabItem { Id = navigationItem.Id, Title = navigationItem.Title, IconType = navigationItem.IconType, ViewModel = viewModel, IsSelected = true, CanClose = navigationItem.Id != "dashboard" }; foreach (var tab in _tabs) { tab.IsSelected = false; } _tabs.Add(newTab); SelectedTab = newTab; } _logger?.LogInformation("Router 导航到: {Title}", navigationItem.Title); } private NavigationItem? FindNavigationItemByViewModel(IRoutableViewModel viewModel) { foreach (var item in _navigationItems) { if (item.ViewModel == viewModel) { return item; } foreach (var child in item.Children) { if (child.ViewModel == viewModel) { return child; } } } return null; } private void SelectTab(TabItem tab) { if (tab == null) return; foreach (var t in _tabs) { t.IsSelected = false; } tab.IsSelected = true; SelectedTab = tab; // 使用 Router 导航到对应的 ViewModel if (tab.ViewModel != null) { _screen.Router.Navigate.Execute(tab.ViewModel); } _logger?.LogInformation("选择标签页: {Title}", tab.Title); } private void CloseTab(TabItem tab) { if (tab == null || !tab.CanClose) return; var tabIndex = _tabs.IndexOf(tab); _tabs.Remove(tab); if (tab.IsSelected && _tabs.Count > 0) { var newSelectedIndex = Math.Min(tabIndex, _tabs.Count - 1); _tabs[newSelectedIndex].IsSelected = true; SelectedTab = _tabs[newSelectedIndex]; // 导航到新选中的标签页 var newSelectedViewModel = _tabs[newSelectedIndex].ViewModel; if (newSelectedViewModel != null) { _screen.Router.Navigate.Execute(newSelectedViewModel); } } _logger?.LogInformation("关闭标签页: {Title}", tab.Title); } }