commit 5dff208e2ca1ae45ed5d8f13a9de1d77a285dadb Author: sanchime <61903865+sanchime@users.noreply.github.com> Date: Tue Oct 15 10:23:51 2024 +0800 初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a1e1fb7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,291 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +.gitea/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# VS Code +.vscode/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs \ No newline at end of file diff --git a/Wpf.NavigationDemo.sln b/Wpf.NavigationDemo.sln new file mode 100644 index 0000000..cfce137 --- /dev/null +++ b/Wpf.NavigationDemo.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wpf.NavigationDemo", "Wpf.NavigationDemo\Wpf.NavigationDemo.csproj", "{BD0E0F51-1354-4D4D-8A54-C8475C51D100}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BD0E0F51-1354-4D4D-8A54-C8475C51D100}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD0E0F51-1354-4D4D-8A54-C8475C51D100}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD0E0F51-1354-4D4D-8A54-C8475C51D100}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD0E0F51-1354-4D4D-8A54-C8475C51D100}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BB3C24C9-113E-4DE8-86B8-7BF13D2A5DAC} + EndGlobalSection +EndGlobal diff --git a/Wpf.NavigationDemo/App.xaml b/Wpf.NavigationDemo/App.xaml new file mode 100644 index 0000000..24ad9c2 --- /dev/null +++ b/Wpf.NavigationDemo/App.xaml @@ -0,0 +1,7 @@ + + + diff --git a/Wpf.NavigationDemo/App.xaml.cs b/Wpf.NavigationDemo/App.xaml.cs new file mode 100644 index 0000000..5c04da7 --- /dev/null +++ b/Wpf.NavigationDemo/App.xaml.cs @@ -0,0 +1,44 @@ +using System.Configuration; +using System.Data; +using System.Diagnostics.CodeAnalysis; +using System.Windows; +using Wpf.NavigationDemo.Extensions; +using Wpf.NavigationDemo.ViewModels; + +namespace Wpf.NavigationDemo +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public new static App Current => (App)Application.Current; + + [MaybeNull] + public IServiceProvider ServiceProvider { get; private set; } + + + [MemberNotNull(nameof(ServiceProvider))] + protected override void OnStartup(StartupEventArgs e) + { + var services = new ServiceCollection(); + + services.AddSingleton(p => new MainWindow + { + DataContext = p.GetRequiredService() + }); + services.AddSingleton(); + + services.AddSingleton(); + services.AddNavigationServices(typeof(App).Assembly); + + ServiceProvider = services.BuildServiceProvider(); + + this.MainWindow = ServiceProvider.GetRequiredService(); + + this.MainWindow.Show(); + } + + } + +} diff --git a/Wpf.NavigationDemo/AssemblyInfo.cs b/Wpf.NavigationDemo/AssemblyInfo.cs new file mode 100644 index 0000000..b0ec827 --- /dev/null +++ b/Wpf.NavigationDemo/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Wpf.NavigationDemo/DefaultNavigationManager.cs b/Wpf.NavigationDemo/DefaultNavigationManager.cs new file mode 100644 index 0000000..1c006fb --- /dev/null +++ b/Wpf.NavigationDemo/DefaultNavigationManager.cs @@ -0,0 +1,14 @@ +namespace Wpf.NavigationDemo; + +public class DefaultNavigationManager(IServiceProvider provider, INavigationService service) : INavigationManager +{ + public INavigation NavigateTo(string route, NavigationOption options) + { + var pageType = service.GetPageType(route); + + ArgumentNullException.ThrowIfNull(pageType); + + return (INavigation)provider.GetRequiredService(pageType); + + } +} diff --git a/Wpf.NavigationDemo/Extensions/NavigationRegisterServiceExtensions.cs b/Wpf.NavigationDemo/Extensions/NavigationRegisterServiceExtensions.cs new file mode 100644 index 0000000..c5d86ec --- /dev/null +++ b/Wpf.NavigationDemo/Extensions/NavigationRegisterServiceExtensions.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.DependencyInjection.Extensions; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Wpf.NavigationDemo.Extensions; + +public static class NavigationRegisterServiceExtensions +{ + public static IServiceCollection AddNavigationServices(this IServiceCollection services, params Assembly[] assemblies) + { + if (assemblies.Length == 0) + { + assemblies = [Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly(), Assembly.GetCallingAssembly()]; + } + + // 注入对话框实例集合 + var navigations = assemblies.Distinct().SelectMany(x => x.GetTypes()).Where(x => + !x.IsAbstract + && !x.IsInterface + && !x.IsGenericType + && !x.IsNested + && x.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(INavigation<>))); + + + NavigationService navigationService = new NavigationService(); + + if (navigations?.Any() is true) + { + + foreach (var navigation in navigations) + { + var interfaces = navigation.GetInterfaces(); + + var navigationInterfaceType = interfaces.Single(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(INavigation<>)); + + services.TryAddTransient(navigationInterfaceType, navigation); + + string pageRoute = navigation.Name.Replace("Page", "").Replace("View", ""); + + navigationService.AddPage(pageRoute, navigationInterfaceType); + } + } + + services.AddSingleton(navigationService); + + return services; + } +} diff --git a/Wpf.NavigationDemo/GlobalUsings.cs b/Wpf.NavigationDemo/GlobalUsings.cs new file mode 100644 index 0000000..dbf8ba4 --- /dev/null +++ b/Wpf.NavigationDemo/GlobalUsings.cs @@ -0,0 +1,6 @@ +global using Microsoft.Extensions.DependencyInjection; +global using CommunityToolkit.Mvvm.ComponentModel; +global using CommunityToolkit.Mvvm.Input; +global using System.Diagnostics.CodeAnalysis; +global using System.Collections.ObjectModel; +global using Wpf.NavigationDemo.Models; \ No newline at end of file diff --git a/Wpf.NavigationDemo/MainWindow.xaml b/Wpf.NavigationDemo/MainWindow.xaml new file mode 100644 index 0000000..3a9557f --- /dev/null +++ b/Wpf.NavigationDemo/MainWindow.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wpf.NavigationDemo/MainWindow.xaml.cs b/Wpf.NavigationDemo/MainWindow.xaml.cs new file mode 100644 index 0000000..4ea050d --- /dev/null +++ b/Wpf.NavigationDemo/MainWindow.xaml.cs @@ -0,0 +1,24 @@ +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Wpf.NavigationDemo +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/Wpf.NavigationDemo/Models/SidebarMenuItem.cs b/Wpf.NavigationDemo/Models/SidebarMenuItem.cs new file mode 100644 index 0000000..97a4d82 --- /dev/null +++ b/Wpf.NavigationDemo/Models/SidebarMenuItem.cs @@ -0,0 +1,3 @@ +namespace Wpf.NavigationDemo.Models; + +public record SidebarMenuItem(string Title, string Route); diff --git a/Wpf.NavigationDemo/NavigationService.cs b/Wpf.NavigationDemo/NavigationService.cs new file mode 100644 index 0000000..a740a87 --- /dev/null +++ b/Wpf.NavigationDemo/NavigationService.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wpf.NavigationDemo; + +public class NavigationService : INavigationService +{ + + private readonly Dictionary _pages = []; + + internal void AddPage(string route, Type type) + { + _pages.TryAdd(route, type); + } + + public Type GetPageType(string route) + { + _pages.TryGetValue(route, out var type); + + return type!; + } +} diff --git a/Wpf.NavigationDemo/Primitives/INavigation.cs b/Wpf.NavigationDemo/Primitives/INavigation.cs new file mode 100644 index 0000000..11f264e --- /dev/null +++ b/Wpf.NavigationDemo/Primitives/INavigation.cs @@ -0,0 +1,8 @@ +namespace Wpf.NavigationDemo; + +public interface INavigation : INavigation +{ + TViewModel ViewModel { get; } +} + +public interface INavigation; diff --git a/Wpf.NavigationDemo/Primitives/INavigationManager.cs b/Wpf.NavigationDemo/Primitives/INavigationManager.cs new file mode 100644 index 0000000..d27c83b --- /dev/null +++ b/Wpf.NavigationDemo/Primitives/INavigationManager.cs @@ -0,0 +1,6 @@ +namespace Wpf.NavigationDemo; + +public interface INavigationManager +{ + INavigation NavigateTo(string route, NavigationOption options); +} diff --git a/Wpf.NavigationDemo/Primitives/INavigationService.cs b/Wpf.NavigationDemo/Primitives/INavigationService.cs new file mode 100644 index 0000000..deb31f7 --- /dev/null +++ b/Wpf.NavigationDemo/Primitives/INavigationService.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wpf.NavigationDemo; + +public interface INavigationService +{ + Type GetPageType(string route); +} diff --git a/Wpf.NavigationDemo/Primitives/NavigationOption.cs b/Wpf.NavigationDemo/Primitives/NavigationOption.cs new file mode 100644 index 0000000..0f09da4 --- /dev/null +++ b/Wpf.NavigationDemo/Primitives/NavigationOption.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wpf.NavigationDemo; + +public class NavigationOption +{ +} diff --git a/Wpf.NavigationDemo/ViewModels/AboutPageViewModel.cs b/Wpf.NavigationDemo/ViewModels/AboutPageViewModel.cs new file mode 100644 index 0000000..1d8abd9 --- /dev/null +++ b/Wpf.NavigationDemo/ViewModels/AboutPageViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wpf.NavigationDemo.ViewModels; + +public class AboutPageViewModel +{ +} diff --git a/Wpf.NavigationDemo/ViewModels/HomePageViewModel.cs b/Wpf.NavigationDemo/ViewModels/HomePageViewModel.cs new file mode 100644 index 0000000..bcf9735 --- /dev/null +++ b/Wpf.NavigationDemo/ViewModels/HomePageViewModel.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Wpf.NavigationDemo.ViewModels; + +public class HomePageViewModel +{ +} diff --git a/Wpf.NavigationDemo/ViewModels/MainViewModel.cs b/Wpf.NavigationDemo/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..075ddd4 --- /dev/null +++ b/Wpf.NavigationDemo/ViewModels/MainViewModel.cs @@ -0,0 +1,37 @@ +namespace Wpf.NavigationDemo.ViewModels; + +public partial class MainViewModel : ObservableObject +{ + [MaybeNull] + [ObservableProperty] + private INavigation _currentPage; + + [ObservableProperty] + private ObservableCollection _menuItems = []; + + [ObservableProperty] + private SidebarMenuItem _selectedMenuItem; + + + private INavigationManager _navigationManager; + public MainViewModel(INavigationManager navigationManager) + { + _navigationManager = navigationManager; + + + MenuItems.Add(new SidebarMenuItem("首页", "Home")); + MenuItems.Add(new SidebarMenuItem("关于", "About")); + + SelectedMenuItem = MenuItems.First(); + + } + + + + partial void OnSelectedMenuItemChanged(SidebarMenuItem value) + { + // 预留Option 或为菜单定制 暂时未实现 + CurrentPage = _navigationManager.NavigateTo(value.Route, new NavigationOption()); + } + +} diff --git a/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml b/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml new file mode 100644 index 0000000..d5a4382 --- /dev/null +++ b/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml @@ -0,0 +1,14 @@ + + + + + diff --git a/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml.cs b/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml.cs new file mode 100644 index 0000000..a2609e5 --- /dev/null +++ b/Wpf.NavigationDemo/Views/Pages/AboutPage.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Wpf.NavigationDemo.ViewModels; + +namespace Wpf.NavigationDemo.Views.Pages +{ + /// + /// AboutPage.xaml 的交互逻辑 + /// + public partial class AboutPage : INavigation + { + public AboutPage() + { + InitializeComponent(); + } + + public AboutPageViewModel ViewModel { get; } + } +} diff --git a/Wpf.NavigationDemo/Views/Pages/HomePage.xaml b/Wpf.NavigationDemo/Views/Pages/HomePage.xaml new file mode 100644 index 0000000..0ed49cb --- /dev/null +++ b/Wpf.NavigationDemo/Views/Pages/HomePage.xaml @@ -0,0 +1,14 @@ + + + 首页 + + diff --git a/Wpf.NavigationDemo/Views/Pages/HomePage.xaml.cs b/Wpf.NavigationDemo/Views/Pages/HomePage.xaml.cs new file mode 100644 index 0000000..a84a994 --- /dev/null +++ b/Wpf.NavigationDemo/Views/Pages/HomePage.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Wpf.NavigationDemo.ViewModels; + +namespace Wpf.NavigationDemo.Views.Pages +{ + /// + /// HomePage.xaml 的交互逻辑 + /// + public partial class HomePage : INavigation + { + public HomePage() + { + InitializeComponent(); + } + + public HomePageViewModel ViewModel { get; } + } +} diff --git a/Wpf.NavigationDemo/Wpf.NavigationDemo.csproj b/Wpf.NavigationDemo/Wpf.NavigationDemo.csproj new file mode 100644 index 0000000..f15b3e5 --- /dev/null +++ b/Wpf.NavigationDemo/Wpf.NavigationDemo.csproj @@ -0,0 +1,16 @@ + + + + WinExe + net8.0-windows + enable + enable + true + + + + + + + +