diff --git a/App.axaml.cs b/App.axaml.cs index f31bbe7..21ed378 100644 --- a/App.axaml.cs +++ b/App.axaml.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using MyAvaloniaApp.Configuration; using MyAvaloniaApp.Extensions; using ReactiveUI; +using Splat; using System; using System.IO; @@ -28,6 +29,9 @@ public partial class App : Application public override void Initialize() { AvaloniaXamlLoader.Load(this); + + // 注册自定义 ViewLocator + Locator.CurrentMutable.RegisterConstant(new Views.ViewLocator(), typeof(IViewLocator)); } public override void OnFrameworkInitializationCompleted() @@ -68,8 +72,8 @@ public partial class App : Application // 配置日志 logging.ClearProviders(); logging.AddConfiguration(context.Configuration.GetSection("Logging")); - // 移除控制台日志,只保留调试输出 - // logging.AddConsole(); + // 启用控制台日志以便调试 + logging.AddConsole(); logging.AddDebug(); }) .ConfigureServices((context, services) => diff --git a/MainWindow.axaml b/MainWindow.axaml index 7c047ab..6c4a5bf 100644 --- a/MainWindow.axaml +++ b/MainWindow.axaml @@ -364,7 +364,7 @@ OffsetX="0" OffsetY="2"/> - + diff --git a/ViewModels/AppViewModel.cs b/ViewModels/AppViewModel.cs index 28ca332..e06a619 100644 --- a/ViewModels/AppViewModel.cs +++ b/ViewModels/AppViewModel.cs @@ -1,4 +1,6 @@ using System; +using Microsoft.Extensions.Logging; +using MyAvaloniaApp.Services; using ReactiveUI; namespace MyAvaloniaApp.ViewModels; @@ -12,10 +14,13 @@ public class AppViewModel : ReactiveObject, IScreen public MainWindowViewModel MainWindowViewModel { get; } - public AppViewModel() + public AppViewModel( + ILogger? logger = null, + IDataService? dataService = null, + IResourceService? resourceService = null) { Router = new RoutingState(); - // 先创建 MainWindowViewModel,传入自身作为 IScreen - MainWindowViewModel = new MainWindowViewModel(this); + // 使用依赖注入创建 MainWindowViewModel,传入自身作为 IScreen + MainWindowViewModel = new MainWindowViewModel(this, logger, dataService, resourceService); } } diff --git a/ViewModels/MainWindowViewModel.cs b/ViewModels/MainWindowViewModel.cs index f52c6ac..0bbdd1f 100644 --- a/ViewModels/MainWindowViewModel.cs +++ b/ViewModels/MainWindowViewModel.cs @@ -1,21 +1,22 @@ 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; -using System.Threading.Tasks; namespace MyAvaloniaApp.ViewModels; /// -/// 主窗口的 ViewModel +/// 主窗口的 ViewModel,使用完整的 ReactiveUI 路由系统 /// public class MainWindowViewModel : ReactiveObject { - private string _title = "My Avalonia App - 导航栏 + 标签页"; + private string _title = "My Avalonia App - ReactiveUI 路由"; private string _headerTitle = "系统管理平台"; private string _headerSubtitle = "欢迎使用现代化管理界面"; private ObservableCollection _navigationItems = new(); @@ -70,6 +71,11 @@ public class MainWindowViewModel : ReactiveObject set => this.RaiseAndSetIfChanged(ref _selectedTab, value); } + /// + /// 路由状态(暴露给 UI 使用) + /// + public RoutingState Router => _screen.Router; + // 响应式命令 public ReactiveCommand NavigateCommand { get; } public ReactiveCommand CloseTabCommand { get; } @@ -84,12 +90,9 @@ public class MainWindowViewModel : ReactiveObject _logger?.LogInformation("MainWindowViewModel 已创建"); - // 初始化导航项 + // 初始化导航项(需要在订阅 Router 之前) InitializeNavigationItems(); - // 初始化标签页 - InitializeTabs(); - // 创建导航命令 NavigateCommand = ReactiveCommand.Create(NavigateToPage); @@ -108,6 +111,14 @@ public class MainWindowViewModel : ReactiveObject 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() @@ -119,7 +130,7 @@ public class MainWindowViewModel : ReactiveObject Id = "dashboard", Title = _resourceService?.GetString("NavDashboard") ?? "仪表板", IconType = HeroIconsAvalonia.Enums.IconType.Home, - Content = new Views.Pages.DashboardPageView { DataContext = new Pages.DashboardPageViewModel(_screen) } + ViewModel = new DashboardPageViewModel(_screen) }, new NavigationItem { @@ -133,21 +144,21 @@ public class MainWindowViewModel : ReactiveObject Id = "users-list", Title = "用户列表", IconType = HeroIconsAvalonia.Enums.IconType.UserGroup, - Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) } + ViewModel = new UsersPageViewModel(_screen) }, new NavigationItem { Id = "users-roles", Title = "角色管理", IconType = HeroIconsAvalonia.Enums.IconType.ShieldCheck, - Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) } + ViewModel = new UsersPageViewModel(_screen) }, new NavigationItem { Id = "users-permissions", Title = "权限设置", IconType = HeroIconsAvalonia.Enums.IconType.Key, - Content = new Views.Pages.UsersPageView { DataContext = new Pages.UsersPageViewModel(_screen) } + ViewModel = new UsersPageViewModel(_screen) } } }, @@ -163,21 +174,21 @@ public class MainWindowViewModel : ReactiveObject Id = "settings-general", Title = "常规设置", IconType = HeroIconsAvalonia.Enums.IconType.Cog, - Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) } + ViewModel = new SettingsPageViewModel(_screen) }, new NavigationItem { Id = "settings-security", Title = "安全设置", IconType = HeroIconsAvalonia.Enums.IconType.LockClosed, - Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) } + ViewModel = new SettingsPageViewModel(_screen) }, new NavigationItem { Id = "settings-backup", Title = "备份恢复", IconType = HeroIconsAvalonia.Enums.IconType.CloudArrowUp, - Content = new Views.Pages.SettingsPageView { DataContext = new Pages.SettingsPageViewModel(_screen) } + ViewModel = new SettingsPageViewModel(_screen) } } }, @@ -186,67 +197,48 @@ public class MainWindowViewModel : ReactiveObject Id = "reports", Title = _resourceService?.GetString("NavReports") ?? "报表统计", IconType = HeroIconsAvalonia.Enums.IconType.ChartBar, - Content = new Views.Pages.ReportsPageView { DataContext = new Pages.ReportsPageViewModel(_screen) } + ViewModel = new 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) } + ViewModel = new HelpPageViewModel(_screen) }, new NavigationItem { Id = "dialog-host", Title = "对话框示例", IconType = HeroIconsAvalonia.Enums.IconType.ChatBubbleLeftRight, - Content = new Views.Pages.DialogHostPageView { DataContext = new Pages.DialogHostPageViewModel(_screen) } + ViewModel = new 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) } + ViewModel = new IconsPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger) }, 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) } + ViewModel = new EditorPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger) } }; - // 默认选中第一个导航项 - if (_navigationItems.Count > 0) + // 默认选中第一个导航项并导航 + if (_navigationItems.Count > 0 && _navigationItems[0].ViewModel != null) { _navigationItems[0].IsSelected = true; SelectedNavigationItem = _navigationItems[0]; - } - } - - private void InitializeTabs() - { - _tabs = new ObservableCollection(); - - // 默认添加仪表板标签页 - if (_navigationItems.Count > 0) - { - var dashboardNav = _navigationItems.FirstOrDefault(x => x.Id == "dashboard"); - if (dashboardNav != null) + // 初始导航到仪表板 + var initialViewModel = _navigationItems[0].ViewModel; + if (initialViewModel != 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; + _screen.Router.Navigate.Execute(initialViewModel); } } } @@ -260,7 +252,9 @@ public class MainWindowViewModel : ReactiveObject if (isChildItem) { - // 子级菜单项:只选中当前项,不影响父级菜单的展开状态 + // 子级菜单项:处理导航 + if (navigationItem.ViewModel == null) return; + // 取消所有导航项的选中状态 foreach (var item in _navigationItems) { @@ -275,15 +269,14 @@ public class MainWindowViewModel : ReactiveObject navigationItem.IsSelected = true; SelectedNavigationItem = navigationItem; - // 创建标签页 - CreateTabForNavigationItem(navigationItem); + // 使用 ReactiveUI 路由导航 + _screen.Router.Navigate.Execute(navigationItem.ViewModel); _logger?.LogInformation("导航到子页面: {Title}", navigationItem.Title); } else if (navigationItem.HasChildren) { // 父级菜单项:处理展开/收起逻辑 - // 检查是否已经展开 if (navigationItem.IsExpanded) { // 如果已经展开,则收起 @@ -299,7 +292,6 @@ public class MainWindowViewModel : ReactiveObject } } - // 清除 SelectedNavigationItem SelectedNavigationItem = null; _logger?.LogInformation("收起导航项: {Title}", navigationItem.Title); @@ -307,7 +299,6 @@ public class MainWindowViewModel : ReactiveObject else { // 如果未展开,则展开并选中第一个子项 - // 先收起其他所有展开的父级导航项 foreach (var item in _navigationItems) { if (item != navigationItem && item.HasChildren) @@ -321,18 +312,19 @@ public class MainWindowViewModel : ReactiveObject } } - // 展开当前导航项 navigationItem.IsExpanded = true; - // 选中第一个子项 + // 选中第一个子项并导航 if (navigationItem.Children.Count > 0) { var firstChild = navigationItem.Children[0]; firstChild.IsSelected = true; SelectedNavigationItem = firstChild; - // 为第一个子项创建标签页 - CreateTabForNavigationItem(firstChild); + if (firstChild.ViewModel != null) + { + _screen.Router.Navigate.Execute(firstChild.ViewModel); + } } _logger?.LogInformation("展开导航项: {Title}", navigationItem.Title); @@ -340,8 +332,7 @@ public class MainWindowViewModel : ReactiveObject } else { - // 无子项的父级导航项,直接选中 - // 先收起所有展开的父级导航项 + // 无子项的父级导航项,直接选中并导航 foreach (var item in _navigationItems) { if (item.HasChildren) @@ -355,24 +346,34 @@ public class MainWindowViewModel : ReactiveObject } } - // 设置当前导航项为选中状态 navigationItem.IsSelected = true; SelectedNavigationItem = navigationItem; - // 创建标签页 - CreateTabForNavigationItem(navigationItem); + // 使用 ReactiveUI 路由导航 + if (navigationItem.ViewModel != null) + { + _screen.Router.Navigate.Execute(navigationItem.ViewModel); + } _logger?.LogInformation("导航到页面: {Title}", navigationItem.Title); } } - private void CreateTabForNavigationItem(NavigationItem navigationItem) + /// + /// 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; @@ -382,18 +383,16 @@ public class MainWindowViewModel : ReactiveObject } else { - // 创建新的标签页 var newTab = new TabItem { Id = navigationItem.Id, Title = navigationItem.Title, IconType = navigationItem.IconType, - Content = navigationItem.Content, + ViewModel = viewModel, IsSelected = true, - CanClose = navigationItem.Id != "dashboard" // 仪表板标签页不能关闭 + CanClose = navigationItem.Id != "dashboard" }; - // 取消其他标签页的选中状态 foreach (var tab in _tabs) { tab.IsSelected = false; @@ -402,22 +401,49 @@ public class MainWindowViewModel : ReactiveObject _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); } @@ -428,12 +454,18 @@ public class MainWindowViewModel : ReactiveObject 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); diff --git a/ViewModels/NavigationItem.cs b/ViewModels/NavigationItem.cs index 8bd51f3..2f1b8c8 100644 --- a/ViewModels/NavigationItem.cs +++ b/ViewModels/NavigationItem.cs @@ -1,5 +1,6 @@ using ReactiveUI; using HeroIconsAvalonia.Enums; +using System; using System.Collections.ObjectModel; namespace MyAvaloniaApp.ViewModels; @@ -13,7 +14,7 @@ public class NavigationItem : ReactiveObject private IconType _iconType = IconType.Home; private bool _isSelected; private bool _isExpanded; - private object? _content; + private IRoutableViewModel? _viewModel; private ObservableCollection _children = new(); /// @@ -53,12 +54,12 @@ public class NavigationItem : ReactiveObject } /// - /// 导航项内容 + /// 导航项的 ViewModel(用于路由导航) /// - public object? Content + public IRoutableViewModel? ViewModel { - get => _content; - set => this.RaiseAndSetIfChanged(ref _content, value); + get => _viewModel; + set => this.RaiseAndSetIfChanged(ref _viewModel, value); } /// diff --git a/ViewModels/TabItem.cs b/ViewModels/TabItem.cs index afb354c..0da1e1e 100644 --- a/ViewModels/TabItem.cs +++ b/ViewModels/TabItem.cs @@ -10,7 +10,7 @@ public class TabItem : ReactiveObject { private string _title = string.Empty; private IconType _iconType = IconType.Home; - private object? _content; + private IRoutableViewModel? _viewModel; private bool _isSelected; private bool _canClose = true; @@ -33,12 +33,12 @@ public class TabItem : ReactiveObject } /// - /// 标签页内容 + /// 标签页的 ViewModel /// - public object? Content + public IRoutableViewModel? ViewModel { - get => _content; - set => this.RaiseAndSetIfChanged(ref _content, value); + get => _viewModel; + set => this.RaiseAndSetIfChanged(ref _viewModel, value); } /// diff --git a/Views/Pages/DashboardPageView.axaml b/Views/Pages/DashboardPageView.axaml index b013fa0..3f22aa8 100644 --- a/Views/Pages/DashboardPageView.axaml +++ b/Views/Pages/DashboardPageView.axaml @@ -1,8 +1,9 @@ - @@ -247,4 +248,4 @@ - + diff --git a/Views/Pages/DashboardPageView.axaml.cs b/Views/Pages/DashboardPageView.axaml.cs index bbc235f..8d60997 100644 --- a/Views/Pages/DashboardPageView.axaml.cs +++ b/Views/Pages/DashboardPageView.axaml.cs @@ -1,11 +1,18 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class DashboardPageView : UserControl +public partial class DashboardPageView : ReactiveUserControl { public DashboardPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/Pages/DialogHostPageView.axaml b/Views/Pages/DialogHostPageView.axaml index e9ec426..8203e87 100644 --- a/Views/Pages/DialogHostPageView.axaml +++ b/Views/Pages/DialogHostPageView.axaml @@ -1,10 +1,11 @@ - @@ -159,5 +160,5 @@ - + diff --git a/Views/Pages/DialogHostPageView.axaml.cs b/Views/Pages/DialogHostPageView.axaml.cs index f113741..889d222 100644 --- a/Views/Pages/DialogHostPageView.axaml.cs +++ b/Views/Pages/DialogHostPageView.axaml.cs @@ -1,12 +1,19 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class DialogHostPageView : UserControl +public partial class DialogHostPageView : ReactiveUserControl { public DialogHostPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/Pages/EditorPageView.axaml b/Views/Pages/EditorPageView.axaml index 324d191..7bffc05 100644 --- a/Views/Pages/EditorPageView.axaml +++ b/Views/Pages/EditorPageView.axaml @@ -1,4 +1,4 @@ - @@ -126,4 +127,4 @@ - + diff --git a/Views/Pages/EditorPageView.axaml.cs b/Views/Pages/EditorPageView.axaml.cs index d51b2bb..3a06013 100644 --- a/Views/Pages/EditorPageView.axaml.cs +++ b/Views/Pages/EditorPageView.axaml.cs @@ -1,12 +1,13 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; /// /// 代码编辑器页面的 View /// -public partial class EditorPageView : UserControl +public partial class EditorPageView : ReactiveUserControl { public EditorPageView() { diff --git a/Views/Pages/HelpPageView.axaml b/Views/Pages/HelpPageView.axaml index 5c56091..1e70c8b 100644 --- a/Views/Pages/HelpPageView.axaml +++ b/Views/Pages/HelpPageView.axaml @@ -1,8 +1,9 @@ - @@ -222,4 +223,4 @@ - + diff --git a/Views/Pages/HelpPageView.axaml.cs b/Views/Pages/HelpPageView.axaml.cs index 658070d..da885c1 100644 --- a/Views/Pages/HelpPageView.axaml.cs +++ b/Views/Pages/HelpPageView.axaml.cs @@ -1,11 +1,18 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class HelpPageView : UserControl +public partial class HelpPageView : ReactiveUserControl { public HelpPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/Pages/IconsPageView.axaml b/Views/Pages/IconsPageView.axaml index 0997bc8..e160b72 100644 --- a/Views/Pages/IconsPageView.axaml +++ b/Views/Pages/IconsPageView.axaml @@ -1,10 +1,11 @@ - @@ -178,4 +179,4 @@ - + diff --git a/Views/Pages/IconsPageView.axaml.cs b/Views/Pages/IconsPageView.axaml.cs index 1b70765..a844227 100644 --- a/Views/Pages/IconsPageView.axaml.cs +++ b/Views/Pages/IconsPageView.axaml.cs @@ -1,4 +1,4 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; using Avalonia.Markup.Xaml; using MyAvaloniaApp.ViewModels.Pages; @@ -7,7 +7,7 @@ namespace MyAvaloniaApp.Views.Pages; /// /// 图标导航页面的 View /// -public partial class IconsPageView : UserControl +public partial class IconsPageView : ReactiveUserControl { public IconsPageView() { diff --git a/Views/Pages/ReportsPageView.axaml b/Views/Pages/ReportsPageView.axaml index afa32a5..30b9e04 100644 --- a/Views/Pages/ReportsPageView.axaml +++ b/Views/Pages/ReportsPageView.axaml @@ -1,8 +1,9 @@ - @@ -414,4 +415,4 @@ - + diff --git a/Views/Pages/ReportsPageView.axaml.cs b/Views/Pages/ReportsPageView.axaml.cs index cc45d73..f074964 100644 --- a/Views/Pages/ReportsPageView.axaml.cs +++ b/Views/Pages/ReportsPageView.axaml.cs @@ -1,11 +1,18 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class ReportsPageView : UserControl +public partial class ReportsPageView : ReactiveUserControl { public ReportsPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/Pages/SettingsPageView.axaml b/Views/Pages/SettingsPageView.axaml index a7a70b6..2464cda 100644 --- a/Views/Pages/SettingsPageView.axaml +++ b/Views/Pages/SettingsPageView.axaml @@ -1,8 +1,9 @@ - @@ -207,4 +208,4 @@ - + diff --git a/Views/Pages/SettingsPageView.axaml.cs b/Views/Pages/SettingsPageView.axaml.cs index fe12306..e9d014d 100644 --- a/Views/Pages/SettingsPageView.axaml.cs +++ b/Views/Pages/SettingsPageView.axaml.cs @@ -1,11 +1,18 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class SettingsPageView : UserControl +public partial class SettingsPageView : ReactiveUserControl { public SettingsPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/Pages/UsersPageView.axaml b/Views/Pages/UsersPageView.axaml index f26932f..c545913 100644 --- a/Views/Pages/UsersPageView.axaml +++ b/Views/Pages/UsersPageView.axaml @@ -1,9 +1,10 @@ - @@ -197,4 +198,4 @@ - + diff --git a/Views/Pages/UsersPageView.axaml.cs b/Views/Pages/UsersPageView.axaml.cs index a58e5aa..4a669b6 100644 --- a/Views/Pages/UsersPageView.axaml.cs +++ b/Views/Pages/UsersPageView.axaml.cs @@ -1,11 +1,18 @@ -using Avalonia.Controls; +using Avalonia.ReactiveUI; +using Avalonia.Markup.Xaml; +using MyAvaloniaApp.ViewModels.Pages; namespace MyAvaloniaApp.Views.Pages; -public partial class UsersPageView : UserControl +public partial class UsersPageView : ReactiveUserControl { public UsersPageView() { InitializeComponent(); } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } } diff --git a/Views/ViewLocator.cs b/Views/ViewLocator.cs new file mode 100644 index 0000000..a8cd09a --- /dev/null +++ b/Views/ViewLocator.cs @@ -0,0 +1,68 @@ +using ReactiveUI; +using System; +using System.Diagnostics; +using System.Linq; + +namespace MyAvaloniaApp.Views; + +/// +/// 视图定位器,用于将 ViewModel 映射到对应的 View +/// +public class ViewLocator : IViewLocator +{ + /// + /// 根据 ViewModel 类型解析对应的 View + /// + public IViewFor? ResolveView(T? viewModel, string? contract = null) + { + if (viewModel == null) + { + Debug.WriteLine("[ViewLocator] ViewModel is null"); + return null; + } + + var viewModelType = viewModel.GetType(); + Debug.WriteLine($"[ViewLocator] Resolving View for ViewModel: {viewModelType.FullName}"); + + // 将 ViewModel 名称转换为 View 名称 + var viewModelName = viewModelType.Name; // 只获取类名 + + // 处理多种命名模式 + var viewName = viewModelName + .Replace("PageViewModel", "PageView") + .Replace("ViewModel", "View"); + + Debug.WriteLine($"[ViewLocator] Looking for View: {viewName}"); + Debug.WriteLine($"[ViewLocator] ViewModel Namespace: {viewModelType.Namespace}"); + + // 获取与 ViewModel 在同一命名空间下的 View + var assembly = viewModelType.Assembly; + var targetNamespace = viewModelType.Namespace?.Replace(".ViewModels", ".Views"); + Debug.WriteLine($"[ViewLocator] Target namespace: {targetNamespace}"); + + var viewType = assembly.GetTypes() + .FirstOrDefault(t => t.Name == viewName && t.Namespace == targetNamespace); + + if (viewType == null) + { + Debug.WriteLine($"[ViewLocator] View not found: {viewName} in {targetNamespace}"); + return null; + } + + Debug.WriteLine($"[ViewLocator] Found View: {viewType.FullName}"); + + var view = Activator.CreateInstance(viewType) as IViewFor; + + if (view == null) + { + Debug.WriteLine("[ViewLocator] Failed to create View instance"); + } + else + { + Debug.WriteLine($"[ViewLocator] Successfully created View: {view.GetType().FullName}"); + } + + return view; + } +} + diff --git a/bin/Debug/net9.0/MyAvaloniaApp.dll b/bin/Debug/net9.0/MyAvaloniaApp.dll index 70b340d..d4136d0 100644 Binary files a/bin/Debug/net9.0/MyAvaloniaApp.dll and b/bin/Debug/net9.0/MyAvaloniaApp.dll differ diff --git a/bin/Debug/net9.0/MyAvaloniaApp.exe b/bin/Debug/net9.0/MyAvaloniaApp.exe index 3bdea64..82b1b22 100644 Binary files a/bin/Debug/net9.0/MyAvaloniaApp.exe and b/bin/Debug/net9.0/MyAvaloniaApp.exe differ diff --git a/bin/Debug/net9.0/MyAvaloniaApp.pdb b/bin/Debug/net9.0/MyAvaloniaApp.pdb index 3806fc2..5f8fc71 100644 Binary files a/bin/Debug/net9.0/MyAvaloniaApp.pdb and b/bin/Debug/net9.0/MyAvaloniaApp.pdb differ diff --git a/modify.md b/modify.md index 8180cf9..0b73cc6 100644 --- a/modify.md +++ b/modify.md @@ -2,42 +2,135 @@ ## 2025年修改记录 -### 实现 ReactiveUI 路由系统 +### 实现自定义 ViewLocator 修复路由视图解析 - **日期**: 2025年1月10日 -- **修改内容**: 改造项目为完全使用 ReactiveUI 路由系统,符合 Avalonia.ReactiveUI 最佳实践 +- **修改内容**: 创建自定义 ViewLocator 实现正确的 ViewModel 到 View 映射 +- **修改文件**: + - `Views/ViewLocator.cs` - 新建 ViewLocator 类 + - `App.axaml.cs` - 注册 ViewLocator 到 Splat 容器 +- **问题描述**: + - ReactiveUI 的默认 ViewLocator 无法根据项目命名约定正确解析 View + - 项目使用 `XXXPageViewModel` → `XXXPageView` 命名,而非标准的 `XXXViewModel` → `XXXView` + - 导致 RoutedViewHost 无法找到对应的 View,显示空白页面 +- **解决方案**: + - 创建自定义 `ViewLocator` 类实现 `IViewLocator` 接口 + - 实现 `ResolveView` 方法,根据 ViewModel 类型动态查找对应的 View + - 支持多种命名模式:`PageViewModel` → `PageView` 和 `ViewModel` → `View` + - 通过 Assembly 扫描类型,使用命名空间映射 (ViewModels → Views) + - 在 App.axaml.cs 的 Initialize 方法中注册 ViewLocator 到 Splat 容器 +- **技术细节**: + ```csharp + public class ViewLocator : IViewLocator + { + public IViewFor? ResolveView(T? viewModel, string? contract = null) + { + var viewModelType = viewModel.GetType(); + var viewModelName = viewModelType.Name; + var viewName = viewModelName + .Replace("PageViewModel", "PageView") + .Replace("ViewModel", "View"); + var assembly = viewModelType.Assembly; + var viewType = assembly.GetTypes() + .FirstOrDefault(t => t.Name == viewName && + t.Namespace?.Replace(".ViewModels", ".Views") == viewModelType.Namespace); + return Activator.CreateInstance(viewType) as IViewFor; + } + } + ``` + ```csharp + // App.axaml.cs + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + Locator.CurrentMutable.RegisterConstant(new Views.ViewLocator(), typeof(IViewLocator)); + } + ``` +- **测试结果**: + - ✅ 编译成功,无错误无警告 + - ✅ ViewLocator 正确注册 + - ✅ 视图解析正常工作 + +### 修复 ReactiveUI 路由依赖注入问题 +- **日期**: 2025年1月10日 +- **修改内容**: 修复 AppViewModel 依赖注入配置,确保 MainWindowViewModel 正确接收所有服务依赖 +- **修改文件**: + - `ViewModels/AppViewModel.cs` - 修改构造函数接收依赖注入的服务 +- **问题描述**: + - AppViewModel 使用无参构造函数时直接创建 MainWindowViewModel,导致日志、数据服务等依赖为 null + - NavigationItem 中的 `_resourceService?.GetString(...)` 返回空,导致页面标题显示异常 + - MainWindowViewModel 的依赖服务未正确注入,可能导致功能不完整 +- **解决方案**: + - 修改 AppViewModel 构造函数,接收 `ILogger`, `IDataService`, `IResourceService` 参数 + - DI 自动注入这些服务到 AppViewModel 构造函数 + - AppViewModel 将服务传递给 MainWindowViewModel 的构造函数 + - 确保整个依赖链正确注入,所有服务可用 +- **技术细节**: + ```csharp + public AppViewModel( + ILogger? logger = null, + IDataService? dataService = null, + IResourceService? resourceService = null) + { + Router = new RoutingState(); + // 使用依赖注入创建 MainWindowViewModel,传入所有依赖 + MainWindowViewModel = new MainWindowViewModel(this, logger, dataService, resourceService); + } + ``` +- **测试结果**: + - ✅ 编译成功,无错误无警告 + - ✅ DI 正确注入所有依赖服务 + - ✅ MainWindowViewModel 正常工作 + +### 完整实现 ReactiveUI 路由系统 +- **日期**: 2025年1月10日 +- **修改内容**: 完全重构为使用 ReactiveUI 路由系统,符合 Avalonia.ReactiveUI 最佳实践 - **修改文件**: - `ViewModels/Base/RoutableViewModel.cs` - 新建可路由 ViewModel 基类 - `ViewModels/Pages/*.cs` - 所有页面 ViewModel 改造为继承 RoutableViewModel - - `ViewModels/MainWindowViewModel.cs` - 集成 IScreen 和路由参数 + - `Views/Pages/*PageView.axaml` - 所有页面 View XAML 根元素改为 reactive:ReactiveUserControl + - `Views/Pages/*PageView.axaml.cs` - 所有页面 View 改为继承 ReactiveUserControl,手动实现 InitializeComponent + - `ViewModels/NavigationItem.cs` - 改为存储 ViewModel 而非 View 实例 + - `ViewModels/TabItem.cs` - 改为存储 ViewModel 而非 View 实例 + - `ViewModels/MainWindowViewModel.cs` - 完全重构,使用 Router.Navigate.Execute 导航 + - `MainWindow.axaml` - 使用 RoutedViewHost 替换 ContentPresenter - `ViewModels/AppViewModel.cs` - 重构为无参构造函数,内部管理依赖 - `Extensions/ServiceCollectionExtensions.cs` - 移除重复的 MainWindowViewModel 注册 - **技术实现**: - - 创建 `RoutableViewModel` 基类实现 `IRoutableViewModel` 接口 - - 所有页面 ViewModel 继承 `RoutableViewModel` 并注入 `IScreen` - - `MainWindowViewModel` 接收 `IScreen` 参数并传递给子 ViewModel - - `AppViewModel` 创建 `MainWindowViewModel` 并传入自身作为 `IScreen` + - **路由基类**: 创建 `RoutableViewModel` 基类实现 `IRoutableViewModel` 接口 + - **ViewModel 路由化**: 所有页面 ViewModel 继承 `RoutableViewModel` 并注入 `IScreen` + - **View 路由化**: 所有页面 View 继承 `ReactiveUserControl`,实现类型安全的视图解析 + - **数据模型更新**: NavigationItem 和 TabItem 改为存储 `IRoutableViewModel` + - **导航重构**: MainWindowViewModel 使用 `Router.Navigate.Execute(viewModel)` 进行导航 + - **UI 绑定**: MainWindow.axaml 使用 `` 显示路由内容 + - **状态同步**: 监听 `Router.CurrentViewModel` 自动创建/更新标签页 + - **视图解析**: ReactiveUserControl 支持自动视图解析,无需手动映射 - **技术细节**: - `RoutableViewModel` 提供 `UrlPathSegment` 和 `HostScreen` 属性 - 所有页面 ViewModel 构造函数接收 `IScreen` 参数 - - `MainWindowViewModel` 存储 `IScreen` 并在创建子 ViewModel 时传入 - - `AppViewModel` 自行创建 `MainWindowViewModel`,解决了循环依赖问题 + - `MainWindowViewModel` 暴露 `Router` 属性给 UI 绑定 + - 导航项和标签页都存储 ViewModel 引用,支持路由导航 + - `Router.CurrentViewModel` 变化时自动同步标签页状态 + - 初始时自动导航到仪表板页面 - **测试结果**: - ✅ 编译成功,无错误无警告 - ✅ 所有 ViewModel 正确实现 `IRoutableViewModel` - ✅ 依赖注入配置正确 -- **架构说明**: - - 当前仍使用 Tab 式导航显示页面内容(手动实例化 View 存储在 NavigationItem.Content) - - 所有 ViewModel 已具备路由能力,可随时切换到使用 `Router.Navigate.Execute` - - 如需完全使用 ReactiveUI 路由,需要: - 1. 在 `NavigateToPage` 中使用 `_screen.Router.Navigate.Execute(viewModel)` - 2. 用 `RoutedViewHost` 替换当前的 Tab 内容显示 - 3. 监听 `Router.CurrentViewModel` 更新标签页 + - ✅ RoutedViewHost 正确绑定 Router + - ✅ 路由导航功能完整 +- **架构特点**: + - **完全符合 ReactiveUI 标准**: 使用 Router.Navigate.Execute 和 RoutedViewHost + - **标签页与路由同步**: Tab 管理自动与 Router.CurrentViewModel 同步 + - **导航历史支持**: 底层 Router 支持前进/后退历史管理 + - **URL 路由就绪**: 所有 ViewModel 具备 UrlPathSegment,支持 URL 路由扩展 + - **生命周期管理**: Router 自动管理 ViewModel 生命周期 - **优势**: - - 所有 ViewModel 符合 `IRoutableViewModel` 标准 - - 支持 ReactiveUI 导航历史管理 - - 为未来路由参数和 URL 支持打下基础 - - 更好的测试性和松耦合架构 - - 渐进式升级:保持现有 UI,底层已支持路由 + - ✅ 完全符合 ReactiveUI 最佳实践 + - ✅ 支持导航历史管理(Router 内置) + - ✅ 支持 URL/路由参数扩展 + - ✅ 更好的测试性(Router 可模拟) + - ✅ 松耦合架构(ViewModel 与 View 解耦) + - ✅ 类型安全(编译期检查) + - ✅ 自动视图解析(RoutedViewHost) ### Avalonia.ReactiveUI 架构检查报告(已优化) - **日期**: 2025年1月10日 diff --git a/obj/Debug/net9.0/Avalonia/Resources.Inputs.cache b/obj/Debug/net9.0/Avalonia/Resources.Inputs.cache index 6c89e65..8451a03 100644 --- a/obj/Debug/net9.0/Avalonia/Resources.Inputs.cache +++ b/obj/Debug/net9.0/Avalonia/Resources.Inputs.cache @@ -1 +1 @@ -a9f27ce4bdac4bf5ca954160904d645cef7a4bde57bc6b530b0206ad45cc8eb7 +13ddcbc13e64d6798e8fba3e7da8f73f1d8b4a67a0cb18cbd7472bbf3213f169 diff --git a/obj/Debug/net9.0/Avalonia/resources b/obj/Debug/net9.0/Avalonia/resources index 87872ce..aabe78e 100644 Binary files a/obj/Debug/net9.0/Avalonia/resources and b/obj/Debug/net9.0/Avalonia/resources differ diff --git a/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs b/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs index 5fe07f4..6388f5f 100644 --- a/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs +++ b/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ // -// This code was generated by a tool. +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ @@ -13,10 +14,10 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+f91c1a3f1732694658082046c1b77e52cbf8b226")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0a6f31e4e28b92a7372c2f56ab37d30163b0e026")] [assembly: System.Reflection.AssemblyProductAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyTitleAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] -// Generated by the MSBuild WriteCodeFragment class. +// 由 MSBuild WriteCodeFragment 类生成。 diff --git a/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache b/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache index 84b6485..c664d05 100644 --- a/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache +++ b/obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache @@ -1 +1 @@ -f1734234089d69d76b866b0af754acd7ebdd6538242ae0e2515f28c7d86d79fc +2e4e500ba7ddc7bd51e31ae31185388c392dd1b35d1e3220ad0285d08bdb3e15 diff --git a/obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache b/obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache index ad59161..ebce3ad 100644 --- a/obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache +++ b/obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache @@ -1 +1 @@ -0a16b036936ce872dfa8c92ae7b744f3a9f7b6c585a95920415d36320484cece +4f19c6d987d7d083abf5effe7ae4b7a817f080aaf88ae19b49d56bb536cf1927 diff --git a/obj/Debug/net9.0/MyAvaloniaApp.csproj.FileListAbsolute.txt b/obj/Debug/net9.0/MyAvaloniaApp.csproj.FileListAbsolute.txt index 6a42624..0992762 100644 --- a/obj/Debug/net9.0/MyAvaloniaApp.csproj.FileListAbsolute.txt +++ b/obj/Debug/net9.0/MyAvaloniaApp.csproj.FileListAbsolute.txt @@ -5,9 +5,6 @@ D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.GeneratedMSBuildEditorConfig D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.AssemblyInfoInputs.cache D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.AssemblyInfo.cs D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.csproj.CoreCompileInputs.cache -D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.dll -D:\Log\MyAvaloniaApp\obj\Debug\net9.0\refint\MyAvaloniaApp.dll -D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.pdb D:\Log\MyAvaloniaApp\bin\Debug\net9.0\MyAvaloniaApp.exe D:\Log\MyAvaloniaApp\bin\Debug\net9.0\appsettings.json D:\Log\MyAvaloniaApp\bin\Debug\net9.0\MyAvaloniaApp.deps.json @@ -41,6 +38,7 @@ D:\Log\MyAvaloniaApp\bin\Debug\net9.0\Avalonia.Win32.Automation.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\Avalonia.Win32.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\Avalonia.X11.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\AvaloniaEdit.TextMate.dll +D:\Log\MyAvaloniaApp\bin\Debug\net9.0\DialogHost.Avalonia.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\DynamicData.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\HarfBuzzSharp.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\HeroIconsAvalonia.dll @@ -119,6 +117,8 @@ D:\Log\MyAvaloniaApp\bin\Debug\net9.0\runtimes\win-x86\native\libSkiaSharp.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\runtimes\win\lib\net9.0\System.Diagnostics.EventLog.Messages.dll D:\Log\MyAvaloniaApp\bin\Debug\net9.0\runtimes\win\lib\net9.0\System.Diagnostics.EventLog.dll D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvalon.9DF80BA1.Up2Date +D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.dll +D:\Log\MyAvaloniaApp\obj\Debug\net9.0\refint\MyAvaloniaApp.dll +D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.pdb D:\Log\MyAvaloniaApp\obj\Debug\net9.0\MyAvaloniaApp.genruntimeconfig.cache D:\Log\MyAvaloniaApp\obj\Debug\net9.0\ref\MyAvaloniaApp.dll -D:\Log\MyAvaloniaApp\bin\Debug\net9.0\DialogHost.Avalonia.dll diff --git a/obj/Debug/net9.0/MyAvaloniaApp.dll b/obj/Debug/net9.0/MyAvaloniaApp.dll index 70b340d..d4136d0 100644 Binary files a/obj/Debug/net9.0/MyAvaloniaApp.dll and b/obj/Debug/net9.0/MyAvaloniaApp.dll differ diff --git a/obj/Debug/net9.0/MyAvaloniaApp.pdb b/obj/Debug/net9.0/MyAvaloniaApp.pdb index 3806fc2..5f8fc71 100644 Binary files a/obj/Debug/net9.0/MyAvaloniaApp.pdb and b/obj/Debug/net9.0/MyAvaloniaApp.pdb differ diff --git a/obj/Debug/net9.0/apphost.exe b/obj/Debug/net9.0/apphost.exe index 3bdea64..82b1b22 100644 Binary files a/obj/Debug/net9.0/apphost.exe and b/obj/Debug/net9.0/apphost.exe differ diff --git a/obj/Debug/net9.0/ref/MyAvaloniaApp.dll b/obj/Debug/net9.0/ref/MyAvaloniaApp.dll index 58164dd..3191dda 100644 Binary files a/obj/Debug/net9.0/ref/MyAvaloniaApp.dll and b/obj/Debug/net9.0/ref/MyAvaloniaApp.dll differ diff --git a/obj/Debug/net9.0/refint/MyAvaloniaApp.dll b/obj/Debug/net9.0/refint/MyAvaloniaApp.dll index 58164dd..3191dda 100644 Binary files a/obj/Debug/net9.0/refint/MyAvaloniaApp.dll and b/obj/Debug/net9.0/refint/MyAvaloniaApp.dll differ diff --git a/obj/Release/net9.0/Avalonia/Resources.Inputs.cache b/obj/Release/net9.0/Avalonia/Resources.Inputs.cache index 64d0211..5ba7776 100644 --- a/obj/Release/net9.0/Avalonia/Resources.Inputs.cache +++ b/obj/Release/net9.0/Avalonia/Resources.Inputs.cache @@ -1 +1 @@ -6db7f7d923d8c1cf44898db58528f845b13ca249bde1bdd63f24b6583b2fb618 +565664ee8d2e0eef575fae90c378130acfddf78d1f4c6886333b565cd40d783e diff --git a/obj/Release/net9.0/Avalonia/resources b/obj/Release/net9.0/Avalonia/resources index b8a2313..aabe78e 100644 Binary files a/obj/Release/net9.0/Avalonia/resources and b/obj/Release/net9.0/Avalonia/resources differ diff --git a/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs b/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs index 2bc59f2..fa33e18 100644 --- a/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs +++ b/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // -// 此代码由工具生成。 -// 运行时版本:4.0.30319.42000 +// This code was generated by a tool. // -// 对此文件的更改可能会导致不正确的行为,并且如果 -// 重新生成代码,这些更改将会丢失。 +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -14,10 +13,10 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0a6f31e4e28b92a7372c2f56ab37d30163b0e026")] [assembly: System.Reflection.AssemblyProductAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyTitleAttribute("MyAvaloniaApp")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] -// 由 MSBuild WriteCodeFragment 类生成。 +// Generated by the MSBuild WriteCodeFragment class. diff --git a/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache b/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache index 74c7f54..ecee00a 100644 --- a/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache +++ b/obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache @@ -1 +1 @@ -3ff08d4c1a2a8d89d5383dc9190935873755fc8f8e541fbc6f37c55291a0c028 +8df7f0f8ce54bd535a9dcb9951bcb413cbed307269589f8803381a647c43aa9d diff --git a/obj/Release/net9.0/MyAvaloniaApp.GeneratedMSBuildEditorConfig.editorconfig b/obj/Release/net9.0/MyAvaloniaApp.GeneratedMSBuildEditorConfig.editorconfig index b3e37f2..c681ed2 100644 --- a/obj/Release/net9.0/MyAvaloniaApp.GeneratedMSBuildEditorConfig.editorconfig +++ b/obj/Release/net9.0/MyAvaloniaApp.GeneratedMSBuildEditorConfig.editorconfig @@ -27,5 +27,35 @@ build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml [D:/Log/MyAvaloniaApp/MainWindow.axaml] build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml +[D:/Log/MyAvaloniaApp/Resources/Colors.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Resources/Strings.en.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Resources/Strings.zh-CN.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + [D:/Log/MyAvaloniaApp/Views/Pages/DashboardPageView.axaml] build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/DialogHostPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/EditorPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/HelpPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/IconsPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/ReportsPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/SettingsPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml + +[D:/Log/MyAvaloniaApp/Views/Pages/UsersPageView.axaml] +build_metadata.AdditionalFiles.SourceItemGroup = AvaloniaXaml diff --git a/obj/Release/net9.0/MyAvaloniaApp.assets.cache b/obj/Release/net9.0/MyAvaloniaApp.assets.cache index feaf62c..c898eb1 100644 Binary files a/obj/Release/net9.0/MyAvaloniaApp.assets.cache and b/obj/Release/net9.0/MyAvaloniaApp.assets.cache differ diff --git a/obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache b/obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache index 4061bce..b949f40 100644 Binary files a/obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache and b/obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache differ