Browse Source

ReactiveUI 完成初步 导航栏问题

master
root 1 month ago
parent
commit
aeacc3a660
  1. 8
      App.axaml.cs
  2. 2
      MainWindow.axaml
  3. 11
      ViewModels/AppViewModel.cs
  4. 170
      ViewModels/MainWindowViewModel.cs
  5. 11
      ViewModels/NavigationItem.cs
  6. 10
      ViewModels/TabItem.cs
  7. 5
      Views/Pages/DashboardPageView.axaml
  8. 11
      Views/Pages/DashboardPageView.axaml.cs
  9. 5
      Views/Pages/DialogHostPageView.axaml
  10. 11
      Views/Pages/DialogHostPageView.axaml.cs
  11. 5
      Views/Pages/EditorPageView.axaml
  12. 5
      Views/Pages/EditorPageView.axaml.cs
  13. 5
      Views/Pages/HelpPageView.axaml
  14. 11
      Views/Pages/HelpPageView.axaml.cs
  15. 7
      Views/Pages/IconsPageView.axaml
  16. 4
      Views/Pages/IconsPageView.axaml.cs
  17. 5
      Views/Pages/ReportsPageView.axaml
  18. 11
      Views/Pages/ReportsPageView.axaml.cs
  19. 5
      Views/Pages/SettingsPageView.axaml
  20. 11
      Views/Pages/SettingsPageView.axaml.cs
  21. 5
      Views/Pages/UsersPageView.axaml
  22. 11
      Views/Pages/UsersPageView.axaml.cs
  23. 68
      Views/ViewLocator.cs
  24. BIN
      bin/Debug/net9.0/MyAvaloniaApp.dll
  25. BIN
      bin/Debug/net9.0/MyAvaloniaApp.exe
  26. BIN
      bin/Debug/net9.0/MyAvaloniaApp.pdb
  27. 135
      modify.md
  28. 2
      obj/Debug/net9.0/Avalonia/Resources.Inputs.cache
  29. BIN
      obj/Debug/net9.0/Avalonia/resources
  30. 11
      obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs
  31. 2
      obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache
  32. 2
      obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache
  33. 8
      obj/Debug/net9.0/MyAvaloniaApp.csproj.FileListAbsolute.txt
  34. BIN
      obj/Debug/net9.0/MyAvaloniaApp.dll
  35. BIN
      obj/Debug/net9.0/MyAvaloniaApp.pdb
  36. BIN
      obj/Debug/net9.0/apphost.exe
  37. BIN
      obj/Debug/net9.0/ref/MyAvaloniaApp.dll
  38. BIN
      obj/Debug/net9.0/refint/MyAvaloniaApp.dll
  39. 2
      obj/Release/net9.0/Avalonia/Resources.Inputs.cache
  40. BIN
      obj/Release/net9.0/Avalonia/resources
  41. 11
      obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs
  42. 2
      obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache
  43. 30
      obj/Release/net9.0/MyAvaloniaApp.GeneratedMSBuildEditorConfig.editorconfig
  44. BIN
      obj/Release/net9.0/MyAvaloniaApp.assets.cache
  45. BIN
      obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache

8
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) =>

2
MainWindow.axaml

@ -364,7 +364,7 @@
OffsetX="0"
OffsetY="2"/>
</Border.Effect>
<ContentPresenter Content="{Binding SelectedTab.Content}"/>
<reactive:RoutedViewHost Router="{Binding Router}"/>
</Border>
</Grid>
</Grid>

11
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<MainWindowViewModel>? 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);
}
}

170
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;
/// <summary>
/// 主窗口的 ViewModel
/// 主窗口的 ViewModel,使用完整的 ReactiveUI 路由系统
/// </summary>
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<NavigationItem> _navigationItems = new();
@ -70,6 +71,11 @@ public class MainWindowViewModel : ReactiveObject
set => this.RaiseAndSetIfChanged(ref _selectedTab, value);
}
/// <summary>
/// 路由状态(暴露给 UI 使用)
/// </summary>
public RoutingState Router => _screen.Router;
// 响应式命令
public ReactiveCommand<NavigationItem, Unit> NavigateCommand { get; }
public ReactiveCommand<TabItem, Unit> CloseTabCommand { get; }
@ -84,12 +90,9 @@ public class MainWindowViewModel : ReactiveObject
_logger?.LogInformation("MainWindowViewModel 已创建");
// 初始化导航项
// 初始化导航项(需要在订阅 Router 之前)
InitializeNavigationItems();
// 初始化标签页
InitializeTabs();
// 创建导航命令
NavigateCommand = ReactiveCommand.Create<NavigationItem>(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<Pages.IconsPageViewModel>) }
ViewModel = new IconsPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger<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>) }
ViewModel = new EditorPageViewModel(_screen, _logger as Microsoft.Extensions.Logging.ILogger<EditorPageViewModel>)
}
};
// 默认选中第一个导航项
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<TabItem>();
// 默认添加仪表板标签页
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)
/// <summary>
/// Router.CurrentViewModel 变化时的处理
/// </summary>
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);

11
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<NavigationItem> _children = new();
/// <summary>
@ -53,12 +54,12 @@ public class NavigationItem : ReactiveObject
}
/// <summary>
/// 导航项内容
/// 导航项的 ViewModel(用于路由导航)
/// </summary>
public object? Content
public IRoutableViewModel? ViewModel
{
get => _content;
set => this.RaiseAndSetIfChanged(ref _content, value);
get => _viewModel;
set => this.RaiseAndSetIfChanged(ref _viewModel, value);
}
/// <summary>

10
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
}
/// <summary>
/// 标签页内容
/// 标签页的 ViewModel
/// </summary>
public object? Content
public IRoutableViewModel? ViewModel
{
get => _content;
set => this.RaiseAndSetIfChanged(ref _content, value);
get => _viewModel;
set => this.RaiseAndSetIfChanged(ref _viewModel, value);
}
/// <summary>

5
Views/Pages/DashboardPageView.axaml

@ -1,8 +1,9 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.DashboardPageView"
x:DataType="vm:DashboardPageViewModel">
@ -247,4 +248,4 @@
</Border>
</Grid>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

11
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<DashboardPageViewModel>
{
public DashboardPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

5
Views/Pages/DialogHostPageView.axaml

@ -1,10 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:heroicons="clr-namespace:HeroIconsAvalonia.Controls;assembly=HeroIconsAvalonia"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d"
x:Class="MyAvaloniaApp.Views.Pages.DialogHostPageView"
x:DataType="vm:DialogHostPageViewModel">
@ -159,5 +160,5 @@
</Border>
</Grid>
</dialogHost:DialogHost>
</UserControl>
</reactive:ReactiveUserControl>

11
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<DialogHostPageViewModel>
{
public DialogHostPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

5
Views/Pages/EditorPageView.axaml

@ -1,4 +1,4 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
@ -7,6 +7,7 @@
xmlns:avaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
xmlns:attached="using:MyAvaloniaApp.Attached"
xmlns:heroicons="clr-namespace:HeroIconsAvalonia.Controls;assembly=HeroIconsAvalonia"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
x:Class="MyAvaloniaApp.Views.Pages.EditorPageView"
x:DataType="vm:EditorPageViewModel">
@ -126,4 +127,4 @@
</Border>
</Grid>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

5
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;
/// <summary>
/// 代码编辑器页面的 View
/// </summary>
public partial class EditorPageView : UserControl
public partial class EditorPageView : ReactiveUserControl<EditorPageViewModel>
{
public EditorPageView()
{

5
Views/Pages/HelpPageView.axaml

@ -1,8 +1,9 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.HelpPageView"
x:DataType="vm:HelpPageViewModel">
@ -222,4 +223,4 @@
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

11
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<HelpPageViewModel>
{
public HelpPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

7
Views/Pages/IconsPageView.axaml

@ -1,10 +1,11 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:converters="using:MyAvaloniaApp.Converters"
xmlns:heroicons="clr-namespace:HeroIconsAvalonia.Controls;assembly=HeroIconsAvalonia"
xmlns:heroicons="clr-namespace:HeroIconsAvalonia.Controls;assembly=HeroIconsAvalonia"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.IconsPageView"
x:DataType="vm:IconsPageViewModel">
@ -178,4 +179,4 @@
</ItemsControl>
</ScrollViewer>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

4
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;
/// <summary>
/// 图标导航页面的 View
/// </summary>
public partial class IconsPageView : UserControl
public partial class IconsPageView : ReactiveUserControl<IconsPageViewModel>
{
public IconsPageView()
{

5
Views/Pages/ReportsPageView.axaml

@ -1,8 +1,9 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.ReportsPageView"
x:DataType="vm:ReportsPageViewModel">
@ -414,4 +415,4 @@
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

11
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<ReportsPageViewModel>
{
public ReportsPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

5
Views/Pages/SettingsPageView.axaml

@ -1,8 +1,9 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.SettingsPageView"
x:DataType="vm:SettingsPageViewModel">
@ -207,4 +208,4 @@
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

11
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<SettingsPageViewModel>
{
public SettingsPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

5
Views/Pages/UsersPageView.axaml

@ -1,9 +1,10 @@
<UserControl xmlns="https://github.com/avaloniaui"
<reactive:ReactiveUserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="using:MyAvaloniaApp.ViewModels.Pages"
xmlns:converters="using:MyAvaloniaApp.Converters"
xmlns:reactive="clr-namespace:Avalonia.ReactiveUI;assembly=Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="600"
x:Class="MyAvaloniaApp.Views.Pages.UsersPageView"
x:DataType="vm:UsersPageViewModel">
@ -197,4 +198,4 @@
</Grid>
</Border>
</Grid>
</UserControl>
</reactive:ReactiveUserControl>

11
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<UsersPageViewModel>
{
public UsersPageView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

68
Views/ViewLocator.cs

@ -0,0 +1,68 @@
using ReactiveUI;
using System;
using System.Diagnostics;
using System.Linq;
namespace MyAvaloniaApp.Views;
/// <summary>
/// 视图定位器,用于将 ViewModel 映射到对应的 View
/// </summary>
public class ViewLocator : IViewLocator
{
/// <summary>
/// 根据 ViewModel 类型解析对应的 View
/// </summary>
public IViewFor? ResolveView<T>(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;
}
}

BIN
bin/Debug/net9.0/MyAvaloniaApp.dll

Binary file not shown.

BIN
bin/Debug/net9.0/MyAvaloniaApp.exe

Binary file not shown.

BIN
bin/Debug/net9.0/MyAvaloniaApp.pdb

Binary file not shown.

135
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<T>` 方法,根据 ViewModel 类型动态查找对应的 View
- 支持多种命名模式:`PageViewModel` → `PageView``ViewModel``View`
- 通过 Assembly 扫描类型,使用命名空间映射 (ViewModels → Views)
- 在 App.axaml.cs 的 Initialize 方法中注册 ViewLocator 到 Splat 容器
- **技术细节**:
```csharp
public class ViewLocator : IViewLocator
{
public IViewFor? ResolveView<T>(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<MainWindowViewModel>`, `IDataService`, `IResourceService` 参数
- DI 自动注入这些服务到 AppViewModel 构造函数
- AppViewModel 将服务传递给 MainWindowViewModel 的构造函数
- 确保整个依赖链正确注入,所有服务可用
- **技术细节**:
```csharp
public AppViewModel(
ILogger<MainWindowViewModel>? 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<ViewModel>`,实现类型安全的视图解析
- **数据模型更新**: NavigationItem 和 TabItem 改为存储 `IRoutableViewModel`
- **导航重构**: MainWindowViewModel 使用 `Router.Navigate.Execute(viewModel)` 进行导航
- **UI 绑定**: MainWindow.axaml 使用 `<reactive:RoutedViewHost Router="{Binding Router}"/>` 显示路由内容
- **状态同步**: 监听 `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日

2
obj/Debug/net9.0/Avalonia/Resources.Inputs.cache

@ -1 +1 @@
a9f27ce4bdac4bf5ca954160904d645cef7a4bde57bc6b530b0206ad45cc8eb7
13ddcbc13e64d6798e8fba3e7da8f73f1d8b4a67a0cb18cbd7472bbf3213f169

BIN
obj/Debug/net9.0/Avalonia/resources

Binary file not shown.

11
obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfo.cs

@ -1,9 +1,10 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
@ -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 类生成。

2
obj/Debug/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache

@ -1 +1 @@
f1734234089d69d76b866b0af754acd7ebdd6538242ae0e2515f28c7d86d79fc
2e4e500ba7ddc7bd51e31ae31185388c392dd1b35d1e3220ad0285d08bdb3e15

2
obj/Debug/net9.0/MyAvaloniaApp.csproj.CoreCompileInputs.cache

@ -1 +1 @@
0a16b036936ce872dfa8c92ae7b744f3a9f7b6c585a95920415d36320484cece
4f19c6d987d7d083abf5effe7ae4b7a817f080aaf88ae19b49d56bb536cf1927

8
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

BIN
obj/Debug/net9.0/MyAvaloniaApp.dll

Binary file not shown.

BIN
obj/Debug/net9.0/MyAvaloniaApp.pdb

Binary file not shown.

BIN
obj/Debug/net9.0/apphost.exe

Binary file not shown.

BIN
obj/Debug/net9.0/ref/MyAvaloniaApp.dll

Binary file not shown.

BIN
obj/Debug/net9.0/refint/MyAvaloniaApp.dll

Binary file not shown.

2
obj/Release/net9.0/Avalonia/Resources.Inputs.cache

@ -1 +1 @@
6db7f7d923d8c1cf44898db58528f845b13ca249bde1bdd63f24b6583b2fb618
565664ee8d2e0eef575fae90c378130acfddf78d1f4c6886333b565cd40d783e

BIN
obj/Release/net9.0/Avalonia/resources

Binary file not shown.

11
obj/Release/net9.0/MyAvaloniaApp.AssemblyInfo.cs

@ -1,10 +1,9 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: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.
// </auto-generated>
//------------------------------------------------------------------------------
@ -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.

2
obj/Release/net9.0/MyAvaloniaApp.AssemblyInfoInputs.cache

@ -1 +1 @@
3ff08d4c1a2a8d89d5383dc9190935873755fc8f8e541fbc6f37c55291a0c028
8df7f0f8ce54bd535a9dcb9951bcb413cbed307269589f8803381a647c43aa9d

30
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

BIN
obj/Release/net9.0/MyAvaloniaApp.assets.cache

Binary file not shown.

BIN
obj/Release/net9.0/MyAvaloniaApp.csproj.AssemblyReference.cache

Binary file not shown.
Loading…
Cancel
Save