Skip to content

MainThread.BeginInvokeOnMainThread throws on custom platform backends - Common UI-thread marshaling pattern crashes; Dispatcher works but isn't the documented/recommended path #34101

@Redth

Description

@Redth

MainThread.BeginInvokeOnMainThread() and MainThread.InvokeOnMainThreadAsync() throw NotImplementedInReferenceAssemblyException on custom platform backends, even when Application.Current.Dispatcher works correctly. There should be a way for custom backends to provide a MainThread implementation, or MainThread should delegate to the MAUI Dispatcher when available.

Problem

The MainThread static API is commonly used in MAUI apps (and recommended in docs/samples) for marshaling work to the UI thread:

MainThread.BeginInvokeOnMainThread(() =>
{
    // Update UI
});

On a custom platform backend (e.g. Linux/GTK), this throws:

Microsoft.Maui.ApplicationModel.NotImplementedInReferenceAssemblyException:
This functionality is not implemented in the portable version of this assembly.

Meanwhile, the MAUI Dispatcher works fine:

Application.Current?.Dispatcher.Dispatch(() =>
{
    // This works on Linux/GTK
});

Workaround

We replaced all MainThread usage with Application.Current.Dispatcher:

// Before (crashes on Linux)
MainThread.BeginInvokeOnMainThread(() => page.DisplayAlert(...));

// After (works everywhere)
Application.Current?.Dispatcher.Dispatch(() => page.DisplayAlert(...));

This required changes in every service that previously used MainThread, including alert services, toast notifications, and UI callbacks.

Proposed Solution

  1. Allow MainThread to delegate to Dispatcher: If no platform-specific MainThread implementation is registered, fall back to Application.Current?.Dispatcher instead of throwing.

  2. Expose MainThread as a settable implementation (same pattern as proposed for other Essentials APIs) so custom backends can provide their own:

MainThread.SetDefault(new GtkMainThreadImpl());
  1. Document Dispatcher as the preferred cross-platform pattern and deprecate MainThread for new code, since Dispatcher already works via the MAUI infrastructure.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions