diff --git a/readme.md b/readme.md index 2359e4a..63d6e23 100644 --- a/readme.md +++ b/readme.md @@ -6,6 +6,7 @@ [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.svg?label=Core&color=004880)](https://www.nuget.org/packages/AsyncNavigation) [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.Avalonia.svg?label=Avalonia&color=8b45e0)](https://www.nuget.org/packages/AsyncNavigation.Avalonia) [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.Wpf.svg?label=WPF&color=0078d4)](https://www.nuget.org/packages/AsyncNavigation.Wpf) +[![WinUI 3](https://img.shields.io/badge/WinUI%203-in%20development-orange)](samples/Sample.WinUI) [![License: MIT](https://img.shields.io/github/license/NeverMorewd/AsyncNavigation)](LICENSE) [![.NET](https://img.shields.io/badge/.NET-8.0%2B-512BD4)](https://dotnet.microsoft.com) @@ -31,6 +32,19 @@ --- +## Platform Support + +| Platform | Status | Package / Sample | +|---|---|---| +| Avalonia | Stable | `AsyncNavigation.Avalonia` | +| WPF | Stable | `AsyncNavigation.Wpf` | +| WinUI 3 | **In development** | [`Sample.WinUI`](samples/Sample.WinUI) | + +> [!WARNING] +> WinUI 3 support is under active development. It includes content, items, tab, `NavigationView`, dialog, window, and indicator support, but its APIs and behavior may still change. Test it carefully before using it in production. + +--- + ## Installation ```bash @@ -41,6 +55,8 @@ dotnet add package AsyncNavigation.Avalonia dotnet add package AsyncNavigation.Wpf ``` +WinUI 3 is currently available from source and through the repository sample while development continues. + --- ## Quick Start diff --git a/readme_zh-cn.md b/readme_zh-cn.md index e5e6773..90be970 100644 --- a/readme_zh-cn.md +++ b/readme_zh-cn.md @@ -6,6 +6,7 @@ [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.svg?label=Core&color=004880)](https://www.nuget.org/packages/AsyncNavigation) [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.Avalonia.svg?label=Avalonia&color=8b45e0)](https://www.nuget.org/packages/AsyncNavigation.Avalonia) [![NuGet](https://img.shields.io/nuget/v/AsyncNavigation.Wpf.svg?label=WPF&color=0078d4)](https://www.nuget.org/packages/AsyncNavigation.Wpf) +[![WinUI 3](https://img.shields.io/badge/WinUI%203-%E5%BC%80%E5%8F%91%E4%B8%AD-orange)](samples/Sample.WinUI) [![License: MIT](https://img.shields.io/github/license/NeverMorewd/AsyncNavigation)](LICENSE) [![.NET](https://img.shields.io/badge/.NET-8.0%2B-512BD4)](https://dotnet.microsoft.com) @@ -31,6 +32,19 @@ --- +## 平台支持 + +| 平台 | 状态 | 包 / 示例 | +|---|---|---| +| Avalonia | 稳定 | `AsyncNavigation.Avalonia` | +| WPF | 稳定 | `AsyncNavigation.Wpf` | +| WinUI 3 | **开发中** | [`Sample.WinUI`](samples/Sample.WinUI) | + +> [!WARNING] +> WinUI 3 支持仍处于积极开发阶段。目前已包含 Content、Items、Tab、`NavigationView`、对话框、窗口和加载指示器支持,但 API 与行为仍可能发生变化。在生产环境使用前请充分测试。 + +--- + ## 安装 ```bash @@ -41,6 +55,8 @@ dotnet add package AsyncNavigation.Avalonia dotnet add package AsyncNavigation.Wpf ``` +WinUI 3 目前可通过源码和仓库中的示例项目进行体验,正式包仍在开发中。 + --- ## 快速开始 diff --git a/samples/Directory.Packages.props b/samples/Directory.Packages.props index 71d7ad5..fe1691e 100644 --- a/samples/Directory.Packages.props +++ b/samples/Directory.Packages.props @@ -14,11 +14,14 @@ + + + diff --git a/samples/Sample.Common/MainWindowViewModel.cs b/samples/Sample.Common/MainWindowViewModel.cs index 435295d..f5761c8 100644 --- a/samples/Sample.Common/MainWindowViewModel.cs +++ b/samples/Sample.Common/MainWindowViewModel.cs @@ -155,6 +155,12 @@ private void ShowWindow(string param) var result = _dialogService.ShowWindowDialog(param); } + [ReactiveCommand(CanExecute = nameof(SupportDialog))] + private async Task AsyncShowWindow(string param) + { + await _dialogService.ShowWindowDialogAsync(param); + } + [ReactiveCommand] private async Task GoForward() { diff --git a/samples/Sample.Common/Sample.Common.csproj b/samples/Sample.Common/Sample.Common.csproj index 19ee1c4..625e956 100644 --- a/samples/Sample.Common/Sample.Common.csproj +++ b/samples/Sample.Common/Sample.Common.csproj @@ -1,7 +1,7 @@  - net10.0 + net8.0;net10.0 enable enable diff --git a/samples/Sample.WinUI/App.xaml b/samples/Sample.WinUI/App.xaml new file mode 100644 index 0000000..3e07b22 --- /dev/null +++ b/samples/Sample.WinUI/App.xaml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/samples/Sample.WinUI/App.xaml.cs b/samples/Sample.WinUI/App.xaml.cs new file mode 100644 index 0000000..50c9f98 --- /dev/null +++ b/samples/Sample.WinUI/App.xaml.cs @@ -0,0 +1,74 @@ +using AsyncNavigation; +using AsyncNavigation.Core; +using AsyncNavigation.WinUI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml; +using ReactiveUI.Builder; +using Sample.Common; +using Sample.WinUI.Views; +using Sample.WinUI.Regions; + +namespace Sample.WinUI; + +public partial class App : Application +{ + private Window? _window; + + public App() + { + InitializeComponent(); + } + + protected override void OnLaunched(LaunchActivatedEventArgs args) + { + RxAppBuilder.CreateReactiveUIBuilder() + .WithWinUI() + .BuildApp(); + var services = new ServiceCollection(); + services.AddNavigationSupport() + .AddSingleton() + .RegisterRegionAdapter() + .RegisterView(nameof(LightView)) + .RegisterView(nameof(ItemsRegionView)) + .RegisterView(nameof(ChildContentRegionView)) + .RegisterView(nameof(TabRegionView)) + .RegisterView(nameof(NavigationViewRegionView)) + .RegisterView(nameof(HeavyView)) + .RegisterDialogWindow(nameof(AWindow)) + .RegisterInnerIndicatorProvider() + .RegisterRegionIndicatorProvider() + .RegisterView(nameof(ListBoxRegionView)) + .RegisterRouter((mapper, _) => + { + mapper.MapNavigation("Path_ChildHeavyView", + new NavigationTarget("MainRegion", nameof(ChildContentRegionView)), + new NavigationTarget("ChildContentRegion", nameof(HeavyView))); + mapper.MapNavigation("Path_ChildAView", + new NavigationTarget("MainRegion", nameof(ChildContentRegionView)), + new NavigationTarget("ChildContentRegion", nameof(LightView))); + mapper.MapNavigation("Path_TabHeavyView", + new NavigationTarget("MainRegion", nameof(TabRegionView)), + new NavigationTarget("TabRegion", nameof(HeavyView))); + mapper.MapNavigation("Tab.Tab_A", + new NavigationTarget("MainRegion", nameof(TabRegionView)), + new NavigationTarget("TabRegion", nameof(LightView))) + .WithSegments("Tab", "Tab_A"); + mapper.MapNavigation("Path_UnknownView", new NavigationTarget("UnknownRegion", "UnknownView")) + .WithFallback(new NavigationTarget("MainRegion", nameof(LightView))); + }); + + var serviceProvider = services.BuildServiceProvider(); + Resources[nameof(IconDescriptorConverter)] = serviceProvider.GetRequiredService(); + + _window = new MainWindow + { + Content = new MainPage + { + DataContext = serviceProvider.GetRequiredService() + } + }; + _window.Title = "AsyncNavigation · WinUI 3 Sample"; + _window.AppWindow.Resize(new Windows.Graphics.SizeInt32(1100, 720)); + _window.Activate(); + } +} diff --git a/samples/Sample.WinUI/Converters/BoolToVisibilityConverter.cs b/samples/Sample.WinUI/Converters/BoolToVisibilityConverter.cs new file mode 100644 index 0000000..6675b13 --- /dev/null +++ b/samples/Sample.WinUI/Converters/BoolToVisibilityConverter.cs @@ -0,0 +1,15 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Data; + +namespace Sample.WinUI.Converters; + +public sealed class BoolToVisibilityConverter : IValueConverter +{ + public bool Invert { get; set; } + + public object Convert(object value, Type targetType, object parameter, string language) + => value is bool visible && visible != Invert ? Visibility.Visible : Visibility.Collapsed; + + public object ConvertBack(object value, Type targetType, object parameter, string language) + => throw new NotSupportedException(); +} diff --git a/samples/Sample.WinUI/InnerIndicatorProvider.cs b/samples/Sample.WinUI/InnerIndicatorProvider.cs new file mode 100644 index 0000000..fc2fac8 --- /dev/null +++ b/samples/Sample.WinUI/InnerIndicatorProvider.cs @@ -0,0 +1,39 @@ +using AsyncNavigation; +using AsyncNavigation.WinUI; +using Microsoft.UI; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; + +namespace Sample.WinUI; + +internal sealed class InnerIndicatorProvider : IInnerIndicatorProvider +{ + public bool HasErrorIndicator(NavigationContext context) => true; + public bool HasLoadingIndicator(NavigationContext context) => true; + + public UIElement GetLoadingIndicator(NavigationContext context) + { + var cancel = new Button { Content = "Cancel", HorizontalAlignment = HorizontalAlignment.Center }; + cancel.Click += async (_, _) => + { + cancel.IsEnabled = false; + cancel.Content = "Cancelling…"; + await context.CancelAndWaitAsync(); + }; + var panel = new StackPanel { Spacing = 12, VerticalAlignment = VerticalAlignment.Center }; + panel.Children.Add(new TextBlock { Text = "Loading…", FontSize = 24, HorizontalAlignment = HorizontalAlignment.Center }); + panel.Children.Add(new TextBlock { Text = context.ToString(), TextWrapping = TextWrapping.Wrap, HorizontalAlignment = HorizontalAlignment.Center }); + panel.Children.Add(new ProgressBar { IsIndeterminate = true, Width = 260 }); + panel.Children.Add(cancel); + return new Border { Padding = new Thickness(24), Child = panel }; + } + + public UIElement GetErrorIndicator(NavigationContext context) + { + var panel = new StackPanel { Spacing = 12, VerticalAlignment = VerticalAlignment.Center }; + panel.Children.Add(new TextBlock { Text = "Navigation failed", FontSize = 24, Foreground = new SolidColorBrush(Colors.Red), HorizontalAlignment = HorizontalAlignment.Center }); + panel.Children.Add(new TextBlock { Text = context.ToString(), TextWrapping = TextWrapping.Wrap, HorizontalAlignment = HorizontalAlignment.Center }); + return new Border { Padding = new Thickness(24), Child = panel }; + } +} diff --git a/samples/Sample.WinUI/MainPage.xaml b/samples/Sample.WinUI/MainPage.xaml new file mode 100644 index 0000000..fcc361e --- /dev/null +++ b/samples/Sample.WinUI/MainPage.xaml @@ -0,0 +1,42 @@ + + + + + + +