初始化

This commit is contained in:
sanchime 2024-10-15 10:23:51 +08:00
commit 5dff208e2c
24 changed files with 740 additions and 0 deletions

291
.gitignore vendored Normal file
View File

@ -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

25
Wpf.NavigationDemo.sln Normal file
View File

@ -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

View File

@ -0,0 +1,7 @@
<Application
x:Class="Wpf.NavigationDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf.NavigationDemo">
<Application.Resources />
</Application>

View File

@ -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
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
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<MainViewModel>()
});
services.AddSingleton<MainViewModel>();
services.AddSingleton<INavigationManager, DefaultNavigationManager>();
services.AddNavigationServices(typeof(App).Assembly);
ServiceProvider = services.BuildServiceProvider();
this.MainWindow = ServiceProvider.GetRequiredService<MainWindow>();
this.MainWindow.Show();
}
}
}

View File

@ -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)
)]

View File

@ -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);
}
}

View File

@ -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<INavigationService>(navigationService);
return services;
}
}

View File

@ -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;

View File

@ -0,0 +1,41 @@
<Window
x:Class="Wpf.NavigationDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf.NavigationDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Wpf.NavigationDemo.ViewModels"
Title="MainWindow"
Width="800"
Height="450"
d:DataContext="{d:DesignInstance vm:MainViewModel}"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="200" />
<ColumnDefinition Width="10" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Grid.Column="0">
<ListBox ItemsSource="{Binding MenuItems}" SelectedItem="{Binding SelectedMenuItem}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Content" Value="{Binding Title}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Border>
<GridSplitter Grid.Column="1" />
<Border Grid.Column="2">
<ContentControl Content="{Binding CurrentPage}" />
</Border>
</Grid>
</Window>

View File

@ -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
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,3 @@
namespace Wpf.NavigationDemo.Models;
public record SidebarMenuItem(string Title, string Route);

View File

@ -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<string, Type> _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!;
}
}

View File

@ -0,0 +1,8 @@
namespace Wpf.NavigationDemo;
public interface INavigation<out TViewModel> : INavigation
{
TViewModel ViewModel { get; }
}
public interface INavigation;

View File

@ -0,0 +1,6 @@
namespace Wpf.NavigationDemo;
public interface INavigationManager
{
INavigation NavigateTo(string route, NavigationOption options);
}

View File

@ -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);
}

View File

@ -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
{
}

View File

@ -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
{
}

View File

@ -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
{
}

View File

@ -0,0 +1,37 @@
namespace Wpf.NavigationDemo.ViewModels;
public partial class MainViewModel : ObservableObject
{
[MaybeNull]
[ObservableProperty]
private INavigation _currentPage;
[ObservableProperty]
private ObservableCollection<SidebarMenuItem> _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());
}
}

View File

@ -0,0 +1,14 @@
<UserControl
x:Class="Wpf.NavigationDemo.Views.Pages.AboutPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf.NavigationDemo.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<TextBlock Text="关于页面" />
</Grid>
</UserControl>

View File

@ -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
{
/// <summary>
/// AboutPage.xaml 的交互逻辑
/// </summary>
public partial class AboutPage : INavigation<AboutPageViewModel>
{
public AboutPage()
{
InitializeComponent();
}
public AboutPageViewModel ViewModel { get; }
}
}

View File

@ -0,0 +1,14 @@
<UserControl
x:Class="Wpf.NavigationDemo.Views.Pages.HomePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf.NavigationDemo.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<TextBlock>首页</TextBlock>
</Grid>
</UserControl>

View File

@ -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
{
/// <summary>
/// HomePage.xaml 的交互逻辑
/// </summary>
public partial class HomePage : INavigation<HomePageViewModel>
{
public HomePage()
{
InitializeComponent();
}
public HomePageViewModel ViewModel { get; }
}
}

View File

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
</ItemGroup>
</Project>