Skip to content

Commit f2e8e89

Browse files
authored
Add generic navigation apis to Page Navigation (#22010)
* add page navigation using generic type * add tests * add default impl to INavigation api * fix nullable errors * update api diff * addressed comment * update api * move page externsion to own class * make parameter overload non-optional
1 parent 380bd8a commit f2e8e89

10 files changed

Lines changed: 298 additions & 70 deletions

File tree

api/Avalonia.nupkg.xml

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
33
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
4+
<Suppression>
5+
<DiagnosticId>CP0001</DiagnosticId>
6+
<Target>T:Avalonia.Controls.Chrome.TitleBarDecorations</Target>
7+
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Controls.dll</Left>
8+
<Right>current/Avalonia/lib/net10.0/Avalonia.Controls.dll</Right>
9+
</Suppression>
10+
<Suppression>
11+
<DiagnosticId>CP0001</DiagnosticId>
12+
<Target>T:Avalonia.Controls.Chrome.TitleBarDecorations</Target>
13+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
14+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
15+
</Suppression>
416
<Suppression>
517
<DiagnosticId>CP0002</DiagnosticId>
618
<Target>M:Avalonia.Data.Core.UntypedBindingExpressionBase.get_IsDataValidationEnabled</Target>
@@ -67,18 +79,6 @@
6779
<Left>baseline/Avalonia/lib/net10.0/Avalonia.Base.dll</Left>
6880
<Right>current/Avalonia/lib/net10.0/Avalonia.Base.dll</Right>
6981
</Suppression>
70-
<Suppression>
71-
<DiagnosticId>CP0002</DiagnosticId>
72-
<Target>M:Avalonia.Data.Core.UntypedBindingExpressionBase.get_IsDataValidationEnabled</Target>
73-
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
74-
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
75-
</Suppression>
76-
<Suppression>
77-
<DiagnosticId>CP0002</DiagnosticId>
78-
<Target>M:Avalonia.Data.Core.UntypedBindingExpressionBase.Start</Target>
79-
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
80-
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
81-
</Suppression>
8282
<Suppression>
8383
<DiagnosticId>CP0002</DiagnosticId>
8484
<Target>M:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetFrameThemeVariant(Avalonia.Platform.PlatformThemeVariant)</Target>
@@ -97,6 +97,18 @@
9797
<Left>baseline/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Left>
9898
<Right>current/Avalonia/lib/net10.0/Avalonia.OpenGL.dll</Right>
9999
</Suppression>
100+
<Suppression>
101+
<DiagnosticId>CP0002</DiagnosticId>
102+
<Target>M:Avalonia.Data.Core.UntypedBindingExpressionBase.get_IsDataValidationEnabled</Target>
103+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
104+
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
105+
</Suppression>
106+
<Suppression>
107+
<DiagnosticId>CP0002</DiagnosticId>
108+
<Target>M:Avalonia.Data.Core.UntypedBindingExpressionBase.Start</Target>
109+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
110+
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
111+
</Suppression>
100112
<Suppression>
101113
<DiagnosticId>CP0002</DiagnosticId>
102114
<Target>M:Avalonia.Input.PointerEventArgs.#ctor(Avalonia.Interactivity.RoutedEvent,System.Object,Avalonia.Input.IPointer,Avalonia.Visual,Avalonia.Point,System.UInt64,Avalonia.Input.PointerPointProperties,Avalonia.Input.KeyModifiers,System.Lazy{System.Collections.Generic.IReadOnlyList{Avalonia.Input.Raw.RawPointerPoint}})</Target>
@@ -151,6 +163,36 @@
151163
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Base.dll</Left>
152164
<Right>current/Avalonia/lib/net8.0/Avalonia.Base.dll</Right>
153165
</Suppression>
166+
<Suppression>
167+
<DiagnosticId>CP0002</DiagnosticId>
168+
<Target>F:Avalonia.Controls.Chrome.WindowDrawnDecorations.TitleBarDecorationsProperty</Target>
169+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
170+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
171+
</Suppression>
172+
<Suppression>
173+
<DiagnosticId>CP0002</DiagnosticId>
174+
<Target>M:Avalonia.Controls.Chrome.WindowDrawnDecorations.get_TitleBarDecorations</Target>
175+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
176+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
177+
</Suppression>
178+
<Suppression>
179+
<DiagnosticId>CP0002</DiagnosticId>
180+
<Target>M:Avalonia.Controls.Chrome.WindowDrawnDecorations.GetTitleBarDecorations(Avalonia.StyledElement)</Target>
181+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
182+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
183+
</Suppression>
184+
<Suppression>
185+
<DiagnosticId>CP0002</DiagnosticId>
186+
<Target>M:Avalonia.Controls.Chrome.WindowDrawnDecorations.set_TitleBarDecorations(Avalonia.Controls.Chrome.TitleBarDecorations)</Target>
187+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
188+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
189+
</Suppression>
190+
<Suppression>
191+
<DiagnosticId>CP0002</DiagnosticId>
192+
<Target>M:Avalonia.Controls.Chrome.WindowDrawnDecorations.SetTitleBarDecorations(Avalonia.StyledElement,Avalonia.Controls.Chrome.TitleBarDecorations)</Target>
193+
<Left>baseline/Avalonia/lib/net8.0/Avalonia.Controls.dll</Left>
194+
<Right>current/Avalonia/lib/net8.0/Avalonia.Controls.dll</Right>
195+
</Suppression>
154196
<Suppression>
155197
<DiagnosticId>CP0002</DiagnosticId>
156198
<Target>M:Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.SetFrameThemeVariant(Avalonia.Platform.PlatformThemeVariant)</Target>

samples/ControlCatalog/ViewModels/MainWindowViewModel_PageList.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using ControlCatalog.Pages;
55
using Avalonia.Media;
66
using ControlCatalog.Models;
7+
using System.Threading.Tasks;
78

89
namespace ControlCatalog.ViewModels;
910

@@ -137,5 +138,7 @@ private class HomeSectionBuilder(string title) : List<PageItem>
137138
var iconGeometry = StreamGeometry.Parse(iconPath);
138139
Add(new PageItem(header, () => new TPageType(), iconGeometry, description, title));
139140
}
141+
142+
public async virtual Task Navigate(INavigation navigation) { }
140143
}
141144
}

src/Avalonia.Controls/Page/INavigation.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
namespace Avalonia.Controls
88
{
9+
910
/// <summary>
1011
/// Provides navigation operations for stack-based and modal page navigation.
1112
/// Exposed via <see cref="Page.Navigation"/> when a page is hosted in a NavigationPage.
@@ -44,6 +45,11 @@ public interface INavigation
4445
/// </summary>
4546
Task PushAsync(Page page, IPageTransition? transition);
4647

48+
/// <summary>
49+
/// Pushes <paramref name="page"/> using <paramref name="transition"/> with optional <paramref name="parameter"/>.
50+
/// </summary>
51+
Task PushAsync(Page page, IPageTransition? transition, object? parameter) => Task.CompletedTask;
52+
4753
/// <summary>
4854
/// Pops the top page using the host's default transition.
4955
/// </summary>
@@ -84,6 +90,11 @@ public interface INavigation
8490
/// </summary>
8591
Task ReplaceAsync(Page page, IPageTransition? transition);
8692

93+
/// <summary>
94+
/// Replaces the current top page with <paramref name="page"/> using <paramref name="transition"/> with optional <paramref name="parameter"/>.
95+
/// </summary>
96+
Task ReplaceAsync(Page page, IPageTransition? transition, object? parameter) => Task.CompletedTask;
97+
8798
/// <summary>
8899
/// Pushes <paramref name="page"/> as a modal using the host's modal transition.
89100
/// </summary>
@@ -94,6 +105,11 @@ public interface INavigation
94105
/// </summary>
95106
Task PushModalAsync(Page page, IPageTransition? transition);
96107

108+
/// <summary>
109+
/// Pushes <paramref name="page"/> as a modal using <paramref name="transition"/> with optional <paramref name="parameter"/>.
110+
/// </summary>
111+
Task PushModalAsync(Page page, IPageTransition? transition, object? parameter) => Task.CompletedTask;
112+
97113
/// <summary>
98114
/// Pops the top modal page using the host's modal transition.
99115
/// </summary>

src/Avalonia.Controls/Page/NavigatedFromEventArgs.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Reflection.Metadata;
23

34
namespace Avalonia.Controls
45
{
@@ -18,6 +19,11 @@ public NavigatedFromEventArgs(Page? destinationPage, NavigationType navigationTy
1819
NavigationType = navigationType;
1920
}
2021

22+
public NavigatedFromEventArgs(Page? destinationPage, NavigationType navigationType, object? parameter) : this(destinationPage, navigationType)
23+
{
24+
Parameter = parameter;
25+
}
26+
2127
/// <summary>
2228
/// Gets the page that became active after this navigation.
2329
/// </summary>
@@ -27,5 +33,7 @@ public NavigatedFromEventArgs(Page? destinationPage, NavigationType navigationTy
2733
/// Gets the type of navigation that triggered this event.
2834
/// </summary>
2935
public NavigationType NavigationType { get; }
36+
37+
public object? Parameter { get; }
3038
}
3139
}

src/Avalonia.Controls/Page/NavigatedToEventArgs.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public NavigatedToEventArgs(Page? previousPage, NavigationType navigationType)
1818
NavigationType = navigationType;
1919
}
2020

21+
public NavigatedToEventArgs(Page? previousPage, NavigationType navigationType, object? parameter) : this (previousPage, navigationType)
22+
{
23+
Parameter = parameter;
24+
}
25+
2126
/// <summary>
2227
/// Gets the page that was active before this navigation.
2328
/// </summary>
@@ -27,5 +32,7 @@ public NavigatedToEventArgs(Page? previousPage, NavigationType navigationType)
2732
/// Gets the type of navigation that triggered this event.
2833
/// </summary>
2934
public NavigationType NavigationType { get; }
35+
36+
public object? Parameter { get; }
3037
}
3138
}

src/Avalonia.Controls/Page/NavigatingFromEventArgs.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public NavigatingFromEventArgs(Page? destinationPage, NavigationType navigationT
1818
NavigationType = navigationType;
1919
}
2020

21+
public NavigatingFromEventArgs(Page? destinationPage, NavigationType navigationType, object? parameter) : this(destinationPage, navigationType)
22+
{
23+
Parameter = parameter;
24+
}
25+
2126
/// <summary>
2227
/// Gets the page that will become active after this navigation.
2328
/// </summary>
@@ -32,5 +37,7 @@ public NavigatingFromEventArgs(Page? destinationPage, NavigationType navigationT
3237
/// Gets or sets a value indicating whether the navigation should be cancelled.
3338
/// </summary>
3439
public bool Cancel { get; set; }
40+
41+
public object? Parameter { get; }
3542
}
3643
}

src/Avalonia.Controls/Page/NavigationEventArgs.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Reflection.Metadata;
23

34
namespace Avalonia.Controls
45
{
@@ -18,6 +19,11 @@ public NavigationEventArgs(Page page, NavigationType navigationType)
1819
NavigationType = navigationType;
1920
}
2021

22+
public NavigationEventArgs(Page page, NavigationType navigationType, object? parameter) : this(page, navigationType)
23+
{
24+
Parameter = parameter;
25+
}
26+
2127
/// <summary>
2228
/// Gets the page involved in the navigation operation.
2329
/// </summary>
@@ -27,5 +33,7 @@ public NavigationEventArgs(Page page, NavigationType navigationType)
2733
/// Gets the type of navigation that triggered this event.
2834
/// </summary>
2935
public NavigationType NavigationType { get; }
36+
37+
public object? Parameter { get; }
3038
}
3139
}

0 commit comments

Comments
 (0)