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
-
Allow MainThread to delegate to Dispatcher: If no platform-specific MainThread implementation is registered, fall back to Application.Current?.Dispatcher instead of throwing.
-
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());
- Document
Dispatcher as the preferred cross-platform pattern and deprecate MainThread for new code, since Dispatcher already works via the MAUI infrastructure.