ReactiveUI 24.0.0
ReactiveUI 24 is a major release. ReactiveUI now runs on the allocation-conscious ReactiveUI.Primitives engine, with System.Reactive becoming optional. This changes public type identities and, for the System.Reactive-compatible distribution, namespaces, so review the migration path before upgrading.
Choose your distribution
Both distributions use the same ReactiveUI.Primitives engine, custom schedulers, and optimized sinks. Choose one package family consistently based on the reactive types you want in your public API.
| You want | Packages | Namespace | Public reactive types |
|---|---|---|---|
| The new lighter default | ReactiveUI, ReactiveUI.WPF, ReactiveUI.WinForms, ReactiveUI.WinUI, ReactiveUI.Maui, ReactiveUI.Blazor, ReactiveUI.AndroidX, etc.
| ReactiveUI
| RxVoid, ISequencer, Signal<T>
|
| ReactiveUI APIs using System.Reactive schedulers | ReactiveUI.Reactive, ReactiveUI.WPF.Reactive, ReactiveUI.WinForms.Reactive, ReactiveUI.WinUI.Reactive, ReactiveUI.Maui.Reactive, ReactiveUI.Blazor.Reactive, etc.
| Primarily ReactiveUI.Reactive and ReactiveUI.Reactive.Builder
| Unit, IScheduler, Subject<T>
|
New default: ReactiveUI.Primitives types
Keeping the existing package names selects the new default distribution. The normal ReactiveUI namespaces remain, but these public reactive types change:
System.Reactive.Concurrency.ISchedulerbecomesReactiveUI.Primitives.Concurrency.ISequencer.System.Reactive.UnitbecomesReactiveUI.Primitives.RxVoid.Subject<T>,BehaviorSubject<T>, andReplaySubject<T>becomeSignal<T>,BehaviorSignal<T>, andReplaySignal<T>.- System.Reactive is no longer a transitive dependency. ReactiveUI.Primitives provides Rx-style operators over
IObservable<T>, so the default distribution does not require System.Reactive for observable composition. System.Reactive can still coexist with the default packages; choose the.Reactivefamily when you specifically want ReactiveUI APIs to use System.Reactive'sISchedulercompatibility seam (together withUnitand subject interop types).
Use System.Reactive schedulers with ReactiveUI: choose the .Reactive packages
Use the .Reactive packages when you want ReactiveUI itself to accept and expose System.Reactive's IScheduler types. Merely referencing or using System.Reactive elsewhere does not require this distribution. Replace each ReactiveUI package with its matching .Reactive package; for example, use ReactiveUI.Reactive with ReactiveUI.WPF.Reactive instead of ReactiveUI with ReactiveUI.WPF.
The compatibility packages intentionally have distinct type identities. Most ReactiveUI APIs move from ReactiveUI to ReactiveUI.Reactive, builder APIs move to ReactiveUI.Reactive.Builder, and platform XAML/CLR namespace mappings may also need updating. This namespace change is part of why version 24 is a major release.
The .Reactive packages are not the old implementation: they use the same Primitives engine and performance work as the default packages, while exposing System.Reactive 7 types at the interop boundary.
Other changes to know about
- DynamicData integration moved out of core. Core routing types such as
RoutingState,IScreen, andRoutedViewHostremain in the main package. DynamicData-backed routing, change-set, collection, and auto-persist helpers now live inReactiveUI.Routing, orReactiveUI.Routing.Reactivefor the System.Reactive distribution. - Hot MVVM paths are substantially faster. Representative .NET 10 benchmarks showed roughly 3–4× faster
WhenAnyValue/ToPropertysubscription and emission, with 5–13× less allocation. Both distributions benefit because both run on Primitives. - AOT-friendly view activation was added. New
IActivatableView.WhenActivatedoverloads accept anIObservable<object?>ViewModel-change source and avoid reflection and trim warnings. - .NET 11 preview targets were added and aligned. MAUI now targets supported .NET 10+ releases; the end-of-life .NET 9 MAUI targets were removed. Existing .NET 9 Windows/WinUI targets remain.
- Several correctness fixes are included.
WhenAnyValueno longer loses a concurrent first change, WPF main-thread scheduling now dispatches correctly from background threads, suspension state is materialized before shutdown persistence, interaction task handlers resume on the captured UI context, and pureObservableMixinshelpers work before builder initialization. - Platform fixes are included. WinForms design-mode detection works on .NET Core and for nested controls. The WPF
.Reactivepackage now resolves its XAML namespace and ships the default theme required byViewModelViewHost. - Two internal-looking public sink types were removed. Consumers of
ReactiveUI.Internal.SingleValueObservable<T>orSyncExecuteObservable<T>should use the equivalentReactiveUI.Primitives.Advancedsignal types (ReturnSignal<T>andStartSignal<T>).
🗞️ What's Changed
💥 Breaking Changes
- 6433b00 refactor!: drop duplicate sinks for Primitives 5.7.0 concretes (#4387) @glennawatson
✨ Features
- 42b4cce feat: re-platform ReactiveUI onto ReactiveUI.Primitives — leaner, faster, System.Reactive optional (#4382) @glennawatson
- 2f34b56 feat: add AOT-friendly WhenActivated for IActivatableView (#4413) @glennawatson
♻️ Refactoring
- ff88f13 refactor(winui): share routed host setup (#4419) @glennawatson
- 873e9c3 refactor: consolidate duplicated reactive plumbing (#4418) @glennawatson
🐛 Fixes
- fed5931 fix: WaitForDispatcherScheduler marshals to UI thread from non-UI threads (fixes #4354) (#4361) @ChrisPulman @Copilot
- c18940e fix: use ObservableMixins helpers before RxAppBuilder initialization (#4410) @glennawatson
- 5a82114 fix(release): use empty MinVer tag prefix to match unprefixed tags @glennawatson
- 4a4efcf fix(wpf): resolve XAML namespace under REACTIVE_SHIM in AutoDataTemplateBindingHook (#4404) @deeferentleeg
- 9f1b734 fix(wpf): ship a default theme in ReactiveUI.WPF.Reactive so ViewModelViewHost renders (#4412) @glennawatson
- 2eb48f2 fix: resume interaction task handlers on the captured context (#4409) @glennawatson
- e5dbcfe fix: Winforms design mode detection regressed (#4369) @xackus
- d9133b6 fix: support .NET Core in winforms activation design mode check (#4358) @xackus
- 69586a4 Fix: WhenAnyValue subscribes to PropertyChanged before reading the initial value (#4381) @dwcullop
⚡ Performance
- 4680609 perf: use custom reactive sinks to improve allocations and performance (#4363) @glennawatson
🧹 General Changes
- 180a40b build: update package dependencies (#4417) @glennawatson
- b37934c ci(security): pin 3rd-party actions to commit SHAs (CodeQL actions/unpinned-tag) @glennawatson
- 2c6f400 build: allow stable packages with net11 previews @glennawatson
- 6dc538e chore: enable the expanded StyleSharp analyzer rule set and resolve all violations (#4385) @ChrisPulman @glennawatson
- 0a1a74e ci(release): grant packages:read so the release workflow can pull the signer image @glennawatson
- 3823cc3 ci(release): add alpha/beta/rc release channel (#4388) @glennawatson
- c9e11d4 chore(deps): update NuGet dependencies to latest (#4389) @glennawatson
- 4680756 ci(release): migrate signing from SSL.com eSigner to Certum SimplySign @glennawatson
- 9b92273 chore(deps): bump NuGet dependencies and drop EOL net9 MAUI targets (#4391) @glennawatson
- 1330c80 chore: Delete MERGE_FOLLOWUPS.md @glennawatson
- e6088d3 chore(deps): adopt the Sharp analyzer suite, update Primitives, modernize (#4414) @glennawatson
- 9fd2d8c chore: remove stray .dotnet-home template cache and gitignore it (#4371) @glennawatson
- 742cb4e ci(release): allow releasing from a historical ref @glennawatson
📦 Dependencies
- dotnet monorepo: 5aa92cc (10.0.8), 30dcf2f (10.0.9), 2715bb2 (10.0.10) @renovate[bot]
- Microsoft.NET.Test.Sdk: 8fb69dc (18.7.0), d4c290b (18.8.1) @renovate[bot]
- Microsoft.SourceLink.GitHub: 1f35503 (10.0.300), 6665a55 (10.0.301) @renovate[bot]
- ca7f343 chore(deps): update microsoft.extensions to 10.0.9 (#4378) @renovate[bot]
- 4068079 chore(deps): update dependency stylesharp.analyzers to 3.11.2 (#4384) @renovate[bot]
- 4908beb chore(deps): update rx.net (system.reactive) to v7 (#4407) @renovate[bot]
- fb0c249 chore(deps): update dependency microsoft.windows.cswinrt to 2.3.1 (#4415) @renovate[bot]
- 0a8fe1d chore(deps): update .net test stack (#4334) @renovate[bot]
- Microsoft.Testing.Platform.MSBuild: ce0fbeb (2.2.3), 6102207 (2.3.1), e0eea47 (2.3.2) @renovate[bot]
- SonarAnalyzer.CSharp: b50c47a (10.27.0.140913), fcf16d8 (10.29.0.143774) @renovate[bot]
- 3f04004 chore(deps): update dependency microsoft.windowsappsdk to 2.3.1 (#4406) @renovate[bot]
- 719f6e6 chore(deps): update dependency microsoft.testing.extensions.codecoverage to 18.7.0 (#4362) @renovate[bot]
- 7033d0c chore(deps): update microsoft.testing (#4395) @renovate[bot]
- b90f96c chore(deps): update actions/setup-dotnet action to v6 (#4405) @renovate[bot]
- Microsoft.Extensions.DependencyModel: 8a7ff35 (10.0.8), 9d9331d (10.0.10) @renovate[bot]
📌 Other
- bd27fbc Fix suspension persistence to materialize app state before shutdown save (#4353) @ChrisPulman
🔗 Full Changelog: 23.2.28...24.0.0
🙌 Contributions
🌱 New contributors since the last release: @deeferentleeg, @dwcullop
💖 Thanks to all the contributors: @ChrisPulman, @deeferentleeg, @dwcullop, @glennawatson, @xackus
🤖 Automated services that contributed: @Copilot, @renovate[bot]