diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props
index e3585ebcda..5fd5935ac9 100644
--- a/src/Directory.Packages.props
+++ b/src/Directory.Packages.props
@@ -6,7 +6,7 @@
20.2.0
- 7.0.0
+ 7.1.0
1.61.38
diff --git a/src/ReactiveUI.Maui/Common/RoutedViewHost.cs b/src/ReactiveUI.Maui/Common/RoutedViewHost.cs
index 572894e9c8..a18a5047ba 100644
--- a/src/ReactiveUI.Maui/Common/RoutedViewHost.cs
+++ b/src/ReactiveUI.Maui/Common/RoutedViewHost.cs
@@ -11,8 +11,6 @@
#else
using ReactiveUI.Maui.Internal;
#endif
-using Splat;
-
#if REACTIVE_SHIM
namespace ReactiveUI.Reactive;
#else
@@ -26,7 +24,7 @@ namespace ReactiveUI;
///
[RequiresUnreferencedCode("This class uses reflection to determine view model types at runtime through ViewLocator, which may be incompatible with trimming.")]
[RequiresDynamicCode("ViewLocator.ResolveView uses reflection which is incompatible with AOT compilation.")]
-public partial class RoutedViewHost : TransitioningContentControl, IActivatableView, IEnableLogger
+public partial class RoutedViewHost : TransitioningContentControl, IActivatableView, IMauiRoutedViewHost
{
/// The router dependency property.
public static readonly DependencyProperty RouterProperty =
@@ -56,14 +54,7 @@ public RoutedViewHost()
HorizontalContentAlignment = HorizontalAlignment.Stretch;
VerticalContentAlignment = VerticalAlignment.Stretch;
- MauiReactiveHelpers.InitializeRoutedViewHost(
- (this, this.Log(), observable => ViewContractObservable = observable),
- (nameof(Router), RouterProperty, () => Router),
- (nameof(ViewContractObservable), ViewContractObservableProperty, () => ViewContractObservable),
- () => ViewContract,
- contract => _viewContract = contract,
- ResolveViewForViewModel,
- _subscriptions);
+ MauiReactiveHelpers.InitializeRoutedViewHost(this, RouterProperty, ViewContractObservableProperty, _subscriptions, ResolveViewForViewModel);
}
/// Gets or sets the of the view model stack.
@@ -107,23 +98,26 @@ public string? ViewContract
///
public IViewLocator? ViewLocator { get; set; }
+ ///
+ void IMauiRoutedViewHost.SetObservedViewContract(string? contract) => _viewContract = contract;
+
/// Resolves and hosts the view for the supplied view model/contract pair.
- /// The view model and contract to resolve a view for.
+ /// The view model and contract to resolve a view for.
[RequiresUnreferencedCode("This method uses reflection to determine the view model type at runtime, which may be incompatible with trimming.")]
[RequiresDynamicCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, "
+ "or generic constraints), trimming can't validate that the requirements of those annotations are met.")]
- private void ResolveViewForViewModel((IRoutableViewModel? viewModel, string? contract) x)
+ private void ResolveViewForViewModel((IRoutableViewModel? viewModel, string? contract) route)
{
- if (x.viewModel is null)
+ if (route.viewModel is null)
{
Content = DefaultContent;
return;
}
var viewLocator = ViewLocator ?? ReactiveUI.ViewLocator.Current;
- var view = (viewLocator.ResolveView(x.viewModel, x.contract) ?? viewLocator.ResolveView(x.viewModel))
- ?? throw new InvalidOperationException($"Couldn't find view for '{x.viewModel}'.");
- view.ViewModel = x.viewModel;
+ var view = (viewLocator.ResolveView(route.viewModel, route.contract) ?? viewLocator.ResolveView(route.viewModel))
+ ?? throw new InvalidOperationException($"Couldn't find view for '{route.viewModel}'.");
+ view.ViewModel = route.viewModel;
Content = view;
}
}
diff --git a/src/ReactiveUI.Maui/Common/RoutedViewHost{TViewModel}.cs b/src/ReactiveUI.Maui/Common/RoutedViewHost{TViewModel}.cs
index ddd0d83a68..bf158a711b 100644
--- a/src/ReactiveUI.Maui/Common/RoutedViewHost{TViewModel}.cs
+++ b/src/ReactiveUI.Maui/Common/RoutedViewHost{TViewModel}.cs
@@ -11,8 +11,6 @@
#else
using ReactiveUI.Maui.Internal;
#endif
-using Splat;
-
#if REACTIVE_SHIM
namespace ReactiveUI.Reactive;
#else
@@ -27,7 +25,7 @@ namespace ReactiveUI;
///
/// The type of the view model. Must have a public parameterless constructor and implement IRoutableViewModel.
public partial class RoutedViewHost<
- [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TViewModel> : TransitioningContentControl, IActivatableView, IEnableLogger
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] TViewModel> : TransitioningContentControl, IActivatableView, IMauiRoutedViewHost
where TViewModel : class, IRoutableViewModel
{
/// The router dependency property.
@@ -58,14 +56,7 @@ public RoutedViewHost()
HorizontalContentAlignment = HorizontalAlignment.Stretch;
VerticalContentAlignment = VerticalAlignment.Stretch;
- MauiReactiveHelpers.InitializeRoutedViewHost(
- (this, this.Log(), observable => ViewContractObservable = observable),
- (nameof(Router), RouterProperty, () => Router),
- (nameof(ViewContractObservable), ViewContractObservableProperty, () => ViewContractObservable),
- () => ViewContract,
- contract => _viewContract = contract,
- ResolveViewForViewModel,
- _subscriptions);
+ MauiReactiveHelpers.InitializeRoutedViewHost(this, RouterProperty, ViewContractObservableProperty, _subscriptions, ResolveViewForViewModel);
}
/// Gets or sets the view locator.
@@ -109,14 +100,17 @@ public string? ViewContract
}
}
+ ///
+ void IMauiRoutedViewHost.SetObservedViewContract(string? contract) => _viewContract = contract;
+
///
/// Resolves and displays the view for the given view model and contract.
/// This method uses the generic ViewLocator.ResolveView{TViewModel} which is AOT-safe.
///
- /// Tuple containing the view model and contract.
- private void ResolveViewForViewModel((IRoutableViewModel? viewModel, string? contract) x)
+ /// Tuple containing the view model and contract.
+ private void ResolveViewForViewModel((IRoutableViewModel? viewModel, string? contract) route)
{
- if (x.viewModel is null)
+ if (route.viewModel is null)
{
Content = DefaultContent;
return;
@@ -125,9 +119,9 @@ private void ResolveViewForViewModel((IRoutableViewModel? viewModel, string? con
var viewLocator = ViewLocator ?? ReactiveUI.ViewLocator.Current;
// Use the generic ResolveView method - this is AOT-safe!
- var view = viewLocator.ResolveView(x.contract) ?? viewLocator.ResolveView()
+ var view = viewLocator.ResolveView(route.contract) ?? viewLocator.ResolveView()
?? throw new InvalidOperationException($"Couldn't find view for '{nameof(TViewModel)}'.");
- view.ViewModel = x.viewModel as TViewModel;
+ view.ViewModel = route.viewModel as TViewModel;
Content = view;
}
}
diff --git a/src/ReactiveUI.Maui/Internal/IMauiRoutedViewHost.cs b/src/ReactiveUI.Maui/Internal/IMauiRoutedViewHost.cs
new file mode 100644
index 0000000000..bf84c1df7b
--- /dev/null
+++ b/src/ReactiveUI.Maui/Internal/IMauiRoutedViewHost.cs
@@ -0,0 +1,29 @@
+// Copyright (c) 2009-2026 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using Splat;
+
+#if REACTIVE_SHIM
+namespace ReactiveUI.Reactive.Maui.Internal;
+#else
+namespace ReactiveUI.Maui.Internal;
+#endif
+
+/// Supplies the host-specific operations used to initialize a WinUI routed host.
+internal interface IMauiRoutedViewHost : IEnableLogger
+{
+ /// Gets the router.
+ RoutingState Router { get; }
+
+ /// Gets or sets the view-contract observable.
+ IObservable ViewContractObservable { get; set; }
+
+ /// Gets the current view contract.
+ string? ViewContract { get; }
+
+ /// Stores the latest observed view contract without replacing its source observable.
+ /// The observed contract.
+ void SetObservedViewContract(string? contract);
+}
diff --git a/src/ReactiveUI.Maui/Internal/MauiReactiveHelpers.cs b/src/ReactiveUI.Maui/Internal/MauiReactiveHelpers.cs
index 96045b4e63..6a1f687c4f 100644
--- a/src/ReactiveUI.Maui/Internal/MauiReactiveHelpers.cs
+++ b/src/ReactiveUI.Maui/Internal/MauiReactiveHelpers.cs
@@ -141,29 +141,27 @@ internal static IObservable CreatePropertyValueObservable(
}
/// Initializes a WinUI routed host and its view-contract subscriptions.
- /// The host, logger, and view-contract setter.
- /// The router property metadata and accessor.
- /// The view-contract observable property metadata and accessor.
- /// Gets the current view contract.
- /// Stores the latest view contract.
- /// Resolves a routed view model and contract.
+ /// The routed-host type.
+ /// The host to initialize.
+ /// The host's router dependency property.
+ /// The host's view-contract observable dependency property.
/// Collects the host subscription.
- internal static void InitializeRoutedViewHost(
- (FrameworkElement Source, IFullLogger Logger, Action> SetViewContractObservable) host,
- (string Name, DependencyProperty Property, Func GetValue) router,
- (string Name, DependencyProperty Property, Func> GetValue) viewContractObservable,
- Func getViewContract,
- Action setViewContract,
- Action<(IRoutableViewModel? viewModel, string? contract)> resolveView,
- MultipleDisposable subscriptions)
+ /// Resolves a routed view model and contract.
+ internal static void InitializeRoutedViewHost(
+ THost host,
+ DependencyProperty routerProperty,
+ DependencyProperty viewContractObservableProperty,
+ MultipleDisposable subscriptions,
+ Action<(IRoutableViewModel? viewModel, string? contract)> resolveView)
+ where THost : FrameworkElement, IMauiRoutedViewHost
{
- host.SetViewContractObservable(CreateViewContractObservable(host.Source, host.Logger));
+ host.ViewContractObservable = CreateViewContractObservable(host, host.Log());
SubscribeRoutedViewHost(
- host.Source,
- router,
- viewContractObservable,
- getViewContract,
- setViewContract,
+ host,
+ (nameof(host.Router), routerProperty, () => host.Router),
+ (nameof(host.ViewContractObservable), viewContractObservableProperty, () => host.ViewContractObservable),
+ () => host.ViewContract,
+ host.SetObservedViewContract,
resolveView,
subscriptions);
}
diff --git a/src/tests/ReactiveUI.Blazor.Tests/ReactiveUI.Blazor.Tests.csproj b/src/tests/ReactiveUI.Blazor.Tests/ReactiveUI.Blazor.Tests.csproj
index 3df0c92aed..3ea128d3ef 100644
--- a/src/tests/ReactiveUI.Blazor.Tests/ReactiveUI.Blazor.Tests.csproj
+++ b/src/tests/ReactiveUI.Blazor.Tests/ReactiveUI.Blazor.Tests.csproj
@@ -9,6 +9,7 @@
$(ReactiveUIModernTargets)
Exe
true
+ false
enable
enable
net10.0-android;net10.0-ios
Exe
+ true
+ false
$(NoWarn);CS1591
diff --git a/src/tests/ReactiveUI.Routing.Tests/ReactiveUI.Routing.Tests.csproj b/src/tests/ReactiveUI.Routing.Tests/ReactiveUI.Routing.Tests.csproj
index 8f581e5280..6e67acca76 100644
--- a/src/tests/ReactiveUI.Routing.Tests/ReactiveUI.Routing.Tests.csproj
+++ b/src/tests/ReactiveUI.Routing.Tests/ReactiveUI.Routing.Tests.csproj
@@ -9,6 +9,8 @@
$(ReactiveUITestingTargets)
Exe
ReactiveUI.Tests
+ true
+ false
diff --git a/src/tests/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj b/src/tests/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj
index 72ec181213..e839f5d667 100644
--- a/src/tests/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj
+++ b/src/tests/ReactiveUI.Splat.Tests/ReactiveUI.Splat.Tests.csproj
@@ -2,6 +2,7 @@
$(ReactiveUITestingTargets)
Exe
+ true
false
diff --git a/src/tests/ReactiveUI.Testing.Tests/ReactiveUI.Testing.Tests.csproj b/src/tests/ReactiveUI.Testing.Tests/ReactiveUI.Testing.Tests.csproj
index 410e7b9135..e5921809c7 100644
--- a/src/tests/ReactiveUI.Testing.Tests/ReactiveUI.Testing.Tests.csproj
+++ b/src/tests/ReactiveUI.Testing.Tests/ReactiveUI.Testing.Tests.csproj
@@ -2,6 +2,8 @@
$(ReactiveUITestingTargets)
Exe
+ true
+ false
netstandard2.0
$(TargetFramework)
diff --git a/src/tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj b/src/tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj
index 0cb93a8579..607e00b719 100644
--- a/src/tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj
+++ b/src/tests/ReactiveUI.Tests/ReactiveUI.Tests.csproj
@@ -8,6 +8,8 @@
$(ReactiveUITestingTargets)
Exe
+ true
+ false
diff --git a/src/tests/ReactiveUI.WinForms.Tests/ReactiveUI.WinForms.Tests.csproj b/src/tests/ReactiveUI.WinForms.Tests/ReactiveUI.WinForms.Tests.csproj
index 9eae3ee806..45c7aa557c 100644
--- a/src/tests/ReactiveUI.WinForms.Tests/ReactiveUI.WinForms.Tests.csproj
+++ b/src/tests/ReactiveUI.WinForms.Tests/ReactiveUI.WinForms.Tests.csproj
@@ -8,6 +8,8 @@
$(ReactiveUITestingUITargets)
Exe
+ true
+ false
diff --git a/src/tests/ReactiveUI.Wpf.Tests/ReactiveUI.Wpf.Tests.csproj b/src/tests/ReactiveUI.Wpf.Tests/ReactiveUI.Wpf.Tests.csproj
index 431e00a13b..d7dcfd7f1f 100644
--- a/src/tests/ReactiveUI.Wpf.Tests/ReactiveUI.Wpf.Tests.csproj
+++ b/src/tests/ReactiveUI.Wpf.Tests/ReactiveUI.Wpf.Tests.csproj
@@ -9,6 +9,8 @@
$(ReactiveUITestingUITargets)
Exe
ReactiveUI.Tests
+ true
+ false