feat: ask an interaction as an observable and run its handlers on a scheduler by glennawatson · Pull Request #151 · reactiveui/ReactiveUI.Binding.SourceGenerators · GitHub
Skip to content

feat: ask an interaction as an observable and run its handlers on a scheduler - #151

Merged
glennawatson merged 1 commit into
mainfrom
fix/interaction-observable-handle
Sep 27, 2026
Merged

glennawatson merged 1 commit into
mainfrom
fix/interaction-observable-handle

Conversation

@glennawatson

Copy link
Copy Markdown
Contributor

Summary

An interaction can be asked as an observable again, and its handlers can run on a scheduler.

  • IInteraction<TInput, TOutput>.Handle(TInput) returns IObservable<TOutput>. Code that holds an interaction through the interface asks the question as it did in ReactiveUI 24. Interaction<,> implements it explicitly.
  • Interaction<,>.WhenHandled(TInput) returns the question as a cold observable. Each subscription calls Handle once, so a subclass that overrides Handle still applies. It fails with UnhandledInteractionException when no handler answers.
  • new Interaction<TInput, TOutput>(handlerScheduler) runs each handler on that scheduler. Pass the main thread's scheduler so a dialog opens on the UI thread. A null scheduler, like the parameterless constructor, runs handlers on the calling thread.
  • Interaction<,>.Handle(TInput) still returns Task<TOutput>. Code written against the current release keeps compiling.

Why

Moving Interaction into ReactiveUI.Binding changed its API by accident.

  • In ReactiveUI 24, Handle returned IObservable<TOutput>, and IInteraction declared it.
  • The move made Handle return Task<TOutput>, removed it from IInteraction, and dropped the constructor that took a handler scheduler.
  • Code upgrading from ReactiveUI 24 that subscribed to Handle, used it in an observable chain, or passed a scheduler no longer compiled.

Breaking changes

A class that implements IInteraction<TInput, TOutput> itself must now implement Handle(TInput), returning IObservable<TOutput>.

  • Code that uses or derives from Interaction<,> is unaffected.

How this was verified

Tests cover each new member, including a scheduler that holds handlers until it runs.

  • The new examples in bindings/BindInteractionExamples.cs run and print their documented output.
  • The Apple target frameworks were built on a Windows host with the Apple workloads. They could not be run.

Notes for the reviewer

The change is in Interactions/IInteraction.cs and Interactions/Interaction.cs.

  • The PublicAPI.txt files are regenerated and only add the new members.
  • WhenHandled goes through Handle rather than walking the handlers itself, so overrides are honoured. Disposing its subscription drops the answer, but a handler that is already running still finishes. Handle takes no cancellation token to stop it.
  • The website quotes examples word for word, so the new ones need adding to its interaction page.

Checklist

  • I have read the Contribute guide
  • The PR title follows Conventional Commits
  • Tests cover this change, or the summary says why they do not
  • New or changed public API has XML documentation

@glennawatson
glennawatson enabled auto-merge (squash) September 27, 2026 12:20
@codecov

codecov Bot commented Sep 27, 2026

Copy link
Copy Markdown

@sonarqubecloud

Copy link
Copy Markdown

@glennawatson
glennawatson merged commit eb255f3 into main Sep 27, 2026
22 checks passed
@glennawatson
glennawatson deleted the fix/interaction-observable-handle branch September 27, 2026 12:44
glennawatson added a commit to reactiveui/ReactiveUI that referenced this pull request Sep 27, 2026
## Summary

**ReactiveUI now builds against ReactiveUI.Binding 8.6.0, which lets you
ask an interaction as an observable again.**

- `BindingVersion` in `Directory.Packages.props` is now `8.6.0`.
- `IInteraction<TInput, TOutput>.Handle(TInput)` returns
`IObservable<TOutput>`, as it did in ReactiveUI 24.
- `Interaction<TInput, TOutput>.WhenHandled(TInput)` returns the
question as a cold observable.
- `new Interaction<TInput, TOutput>(handlerScheduler)` runs each handler
on that scheduler, such as `RxSchedulers.MainThreadScheduler`.
- `Interaction<TInput, TOutput>.Handle(TInput)` still returns
`Task<TOutput>`, so code written against 25.0.0 keeps compiling.

## Why

**Moving `Interaction` into ReactiveUI.Binding changed its API by
accident in 25.0.0.** Code upgrading from ReactiveUI 24 that subscribed
to `Handle`, used it in an observable chain, or passed a handler
scheduler stopped compiling. ReactiveUI.Binding 8.6.0
(reactiveui/ReactiveUI.Binding.SourceGenerators#151) restores it.

## Breaking changes

**None for code that uses or derives from `Interaction<TInput,
TOutput>`.** A class that implements `IInteraction<TInput, TOutput>`
itself must implement `Handle(TInput)` returning `IObservable<TOutput>`.
Nothing in this repository does.

## How this was verified

**Every Linux-runnable core test project passes on net10.0 against the
released 8.6.0 packages.**

- `ReactiveUI.Tests` (879), `ReactiveUI.Tests.Reactive` (881),
`ReactiveUI.AOT.Tests` (39), `ReactiveUI.Testing.Tests` (57) and
`ReactiveUI.Builder.Tests` (184) pass.
- The Windows-only and device projects are left to CI.

## Checklist
- [x] I have read the [Contribute
guide](https://www.reactiveui.net/contribute/index.html)
- [x] The PR title follows [Conventional
Commits](https://www.conventionalcommits.org/)
- [x] Tests cover this change, or the summary says why they do not
- [x] New or changed public API has XML documentation
@github-actions

Copy link
Copy Markdown

@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Oct 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant