Skip to content

Avalonia 12 support: dispatcher strategy for Epoxy UIThread APIs #48

@supermomonga

Description

@supermomonga

I'm plannning to submit a PR for Avalonia 12 supporting.
Can I discuss about Avalonia 12's multiple dispatcher?

Avalonia 12 support is being added based on the existing Epoxy.Avalonia11 / Epoxy.Core.Avalonia11 projects.

One migration question needs a design decision: how should Epoxy handle Avalonia 12's dispatcher model?

Avalonia 12 introduced multiple dispatcher support, with one dispatcher per thread. Dispatcher.UIThread is still acceptable for applications, but Avalonia recommends that library/control authors use AvaloniaObject.Dispatcher and Dispatcher.CurrentDispatcher where appropriate, instead of always relying on Dispatcher.UIThread.

Reference:
https://docs.avaloniaui.net/docs/avalonia12-breaking-changes#multiple-dispatchers-support

Current Epoxy behavior:

  • UIThread.Bind() / UIThread.InvokeAsync() are targetless public APIs.
  • Avalonia-specific UI-thread continuation currently uses Dispatcher.UIThread.
  • Exception rethrow paths in async event/command handlers also route through the same targetless UI-thread continuation.
  • Relevant files:
    • src/Epoxy/UIThread.cs
    • src/Epoxy/Supplemental/UIThreadAwaitable.cs
    • src/Epoxy.Core/Internal/InternalUIThread.cs
    • src/Epoxy.Core.Avalonia11/Internal/ContinueOnUIThread.cs
    • src/Epoxy.Core/Internal/InternalWell.cs
    • src/Epoxy.Core/Fountain.cs
    • src/Epoxy.Core/EventBinder.cs
    • src/Epoxy.Core/Command.cs

Possible directions:

  1. Keep using Dispatcher.UIThread for Avalonia 12

    • Pros:
      • Preserves current public API semantics.
      • Smallest implementation change.
      • Multiple UI threads are currently still unsupported in Avalonia.
    • Cons:
      • Does not follow the Avalonia 12 library/control author recommendation.
      • Less future-proof for headless, embedded, or virtual-window scenarios.
  2. Switch Avalonia 12 code to target-object dispatchers where possible

    • Pros:
      • Better aligned with Avalonia 12.
      • More correct when an AvaloniaObject is already available.
      • Better future compatibility.
    • Cons:
      • Targetless APIs such as UIThread.Bind() cannot be fully migrated without changing their semantics.
      • Using Dispatcher.CurrentDispatcher for targetless APIs may bind to the caller's current thread dispatcher, which is not necessarily the intended UI dispatcher.
      • May require new internal paths or public overloads.
  3. Hybrid approach

    • Pros:
      • Preserves existing targetless UIThread.* API behavior by keeping it backed by Dispatcher.UIThread.
      • Better aligned with Avalonia 12 when an AvaloniaObject or control is already available.
      • Allows paths like Fountain / Well / EventBinder to use object-bound dispatching without requiring an immediate public API change.
      • Provides a conservative migration path: improve dispatcher correctness for attached-object flows now, and consider public overloads later only if real use cases require them.
      • Keeps Dispatcher.UIThread available as a fallback for existing targetless continuation and exception rethrow paths.
    • Cons:
      • Epoxy would have two dispatcher semantics in the Avalonia 12 implementation: targetless APIs continue to use Dispatcher.UIThread, while object-bound flows may use AvaloniaObject.Dispatcher.
      • In advanced multiple-dispatcher scenarios, control-bound Epoxy code and later targetless UIThread.* calls could switch to different dispatchers.
      • Ordering, reentrancy, and exception rethrow behavior may become harder to reason about when some continuations are object-bound and others fall back to Dispatcher.UIThread.
      • The implementation and test matrix become more complex because both dispatcher paths and their fallback behavior need to be covered.
      • Partial migration could create unclear expectations for users: Avalonia 12 support would be more dispatcher-aware in attached-object flows, but not uniformly dispatcher-aware across all Epoxy APIs.

What direction should Epoxy take for Avalonia 12?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquestionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions