You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

441 lines
16 KiB

using Microsoft.Extensions.Logging;
using MyAvaloniaApp.Services;
using ReactiveUI;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
namespace MyAvaloniaApp.ViewModels;
/// <summary>
/// 主窗口的 ViewModel
/// </summary>
public class MainWindowViewModel : ReactiveObject
{
private string _title = "My Avalonia App - 导航栏 + 标签页";
private string _headerTitle = "系统管理平台";
private string _headerSubtitle = "欢迎使用现代化管理界面";
private ObservableCollection<NavigationItem> _navigationItems = new();
private ObservableCollection<TabItem> _tabs = new();
private NavigationItem? _selectedNavigationItem;
private TabItem? _selectedTab;
private readonly ILogger<MainWindowViewModel>? _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<NavigationItem> NavigationItems
{
get => _navigationItems;
set => this.RaiseAndSetIfChanged(ref _navigationItems, value);
}
public ObservableCollection<TabItem> 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);
}
// 响应式命令
public ReactiveCommand<NavigationItem, Unit> NavigateCommand { get; }
public ReactiveCommand<TabItem, Unit> CloseTabCommand { get; }
public ReactiveCommand<TabItem, Unit> SelectTabCommand { get; }
public MainWindowViewModel(IScreen screen, ILogger<MainWindowViewModel>? logger = null, IDataService? dataService = null, IResourceService? resourceService = null)
{
_screen = screen;
_logger = logger;
_dataService = dataService;
_resourceService = resourceService;
_logger?.LogInformation("MainWindowViewModel 已创建");
// 初始化导航项
InitializeNavigationItems();
// 初始化标签页
InitializeTabs();
// 创建导航命令
NavigateCommand = ReactiveCommand.Create<NavigationItem>(NavigateToPage);
// 创建关闭标签页命令
CloseTabCommand = ReactiveCommand.Create<TabItem>(CloseTab);
// 创建选择标签页命令
SelectTabCommand = ReactiveCommand.Create<TabItem>(SelectTab);
// 监听导航项选择变化
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));
}
private void InitializeNavigationItems()
{
_navigationItems = new ObservableCollection<NavigationItem>
{
new NavigationItem
{
Id = "dashboard",
Title = _resourceService?.GetString("NavDashboard") ?? "仪表板",
IconType = HeroIconsAvalonia.Enums.IconType.Home,
Content = new Views.Pages.DashboardPageView { DataContext = new Pages.DashboardPageViewModel(_screen) }
},
new NavigationItem
{
Id = "users",
Title = _resourceService?.GetString("NavUsers") ?? "用户管理",
IconType = HeroIconsAvalonia.Enums.IconType.Users,
Children = new ObservableCollection<NavigationItem>
{
new NavigationItem
{
Id = "users-list",
Title = "用户列表",
IconType = HeroIconsAvalonia.Enums.IconType.UserGroup,
Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) }
},
new NavigationItem
{
Id = "users-roles",
Title = "角色管理",
IconType = HeroIconsAvalonia.Enums.IconType.ShieldCheck,
Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) }
},
new NavigationItem
{
Id = "users-permissions",
Title = "权限设置",
IconType = HeroIconsAvalonia.Enums.IconType.Key,
Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) }
}
}
},
new NavigationItem
{
Id = "settings",
Title = _resourceService?.GetString("NavSettings") ?? "系统设置",
IconType = HeroIconsAvalonia.Enums.IconType.Cog6Tooth,
Children = new ObservableCollection<NavigationItem>
{
new NavigationItem
{
Id = "settings-general",
Title = "常规设置",
IconType = HeroIconsAvalonia.Enums.IconType.Cog,
Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) }
},
new NavigationItem
{
Id = "settings-security",
Title = "安全设置",
IconType = HeroIconsAvalonia.Enums.IconType.LockClosed,
Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) }
},
new NavigationItem
{
Id = "settings-backup",
Title = "备份恢复",
IconType = HeroIconsAvalonia.Enums.IconType.CloudArrowUp,
Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) }
}
}
},
new NavigationItem
{
Id = "reports",
Title = _resourceService?.GetString("NavReports") ?? "报表统计",
IconType = HeroIconsAvalonia.Enums.IconType.ChartBar,
Content = new Views.Pages.ReportsPageView { DataContext = new Pages.ReportsPageViewModel(_screen) }
},
new NavigationItem
{
Id = "help",
Title = _resourceService?.GetString("NavHelp") ?? "帮助中心",
IconType = HeroIconsAvalonia.Enums.IconType.QuestionMarkCircle,
Content = new Views.Pages.HelpPageView { DataContext = new Pages.HelpPageViewModel(_screen) }
},
new NavigationItem
{
Id = "dialog-host",
Title = "对话框示例",
IconType = HeroIconsAvalonia.Enums.IconType.ChatBubbleLeftRight,
Content = new Views.Pages.DialogHostPageView { DataContext = new Pages.DialogHostPageViewModel(_screen) }
},
new NavigationItem
{
Id = "icons",
Title = _resourceService?.GetString("NavIcons") ?? "图标库",
IconType = HeroIconsAvalonia.Enums.IconType.Sparkles,
Content = new Views.Pages.IconsPageView { DataContext = new Pages.IconsPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger<Pages.IconsPageViewModel>) }
},
new NavigationItem
{
Id = "editor",
Title = "代码编辑器",
IconType = HeroIconsAvalonia.Enums.IconType.CodeBracket,
Content = new Views.Pages.EditorPageView { DataContext = new Pages.EditorPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger<Pages.EditorPageViewModel>) }
}
};
// 默认选中第一个导航项
if (_navigationItems.Count > 0)
{
_navigationItems[0].IsSelected = true;
SelectedNavigationItem = _navigationItems[0];
}
}
private void InitializeTabs()
{
_tabs = new ObservableCollection<TabItem>();
// 默认添加仪表板标签页
if (_navigationItems.Count > 0)
{
var dashboardNav = _navigationItems.FirstOrDefault(x => x.Id == "dashboard");
if (dashboardNav != null)
{
var dashboardTab = new TabItem
{
Id = "dashboard",
Title = _resourceService?.GetString("PageDashboard") ?? "仪表板",
IconType = HeroIconsAvalonia.Enums.IconType.Home,
Content = dashboardNav.Content,
IsSelected = true,
CanClose = false
};
_tabs.Add(dashboardTab);
SelectedTab = dashboardTab;
}
}
}
private void NavigateToPage(NavigationItem navigationItem)
{
if (navigationItem == null) return;
// 检查是否是子级菜单项
bool isChildItem = _navigationItems.Any(parent => parent.Children.Contains(navigationItem));
if (isChildItem)
{
// 子级菜单项:只选中当前项,不影响父级菜单的展开状态
// 取消所有导航项的选中状态
foreach (var item in _navigationItems)
{
item.IsSelected = false;
foreach (var child in item.Children)
{
child.IsSelected = false;
}
}
// 设置当前子项为选中状态
navigationItem.IsSelected = true;
SelectedNavigationItem = navigationItem;
// 创建标签页
CreateTabForNavigationItem(navigationItem);
_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
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;
// 为第一个子项创建标签页
CreateTabForNavigationItem(firstChild);
}
_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;
// 创建标签页
CreateTabForNavigationItem(navigationItem);
_logger?.LogInformation("导航到页面: {Title}", navigationItem.Title);
}
}
private void CreateTabForNavigationItem(NavigationItem navigationItem)
{
// 检查是否已经存在对应的标签页
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,
Content = navigationItem.Content,
IsSelected = true,
CanClose = navigationItem.Id != "dashboard" // 仪表板标签页不能关闭
};
// 取消其他标签页的选中状态
foreach (var tab in _tabs)
{
tab.IsSelected = false;
}
_tabs.Add(newTab);
SelectedTab = newTab;
}
}
private void SelectTab(TabItem tab)
{
if (tab == null) return;
// 取消所有标签页的选中状态
foreach (var t in _tabs)
{
t.IsSelected = false;
}
// 设置当前标签页为选中状态
tab.IsSelected = true;
SelectedTab = tab;
_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];
}
_logger?.LogInformation("关闭标签页: {Title}", tab.Title);
}
}