MaterialDesignInXAML/MaterialDesignInXamlToolkit · error · InvalidOperationException

SnackbarMessageQueue must be created in a dispatcher thread

Error message

SnackbarMessageQueue must be created in a dispatcher thread

What it means

The single-argument constructor SnackbarMessageQueue(TimeSpan) resolves the current thread's Dispatcher via Dispatcher.FromThread(Thread.CurrentThread). On a thread with no dispatcher (a Task, thread-pool, or test thread) this returns null and the constructor throws InvalidOperationException, because the queue needs a dispatcher to schedule UI work.

Source

Thrown at src/MaterialDesignThemes.Wpf/SnackbarMessageQueue.cs:120

            {
                _waitHandle.Dispose();
                _isDisposed = true;
            }
            _disposedWaitHandle.Set();
            _disposedWaitHandle.Dispose();
        }
    }

    #endregion

    public SnackbarMessageQueue()
        : this(TimeSpan.FromSeconds(3))
    {
    }

    public SnackbarMessageQueue(TimeSpan messageDuration)
        : this(messageDuration, Dispatcher.FromThread(Thread.CurrentThread)
                      ?? throw new InvalidOperationException("SnackbarMessageQueue must be created in a dispatcher thread"))
    { }

    public SnackbarMessageQueue(TimeSpan messageDuration, Dispatcher dispatcher)
    {
        _messageDuration = messageDuration;
        _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
    }

    //oh if only I had Disposable.Create in this lib :)  tempted to copy it in like dragablz,
    //but this is an internal method so no one will know my dirty Action disposer...
    internal Action Pair(Snackbar snackbar)
    {
        if (snackbar is null) throw new ArgumentNullException(nameof(snackbar));

        _pairedSnackbars.Add(snackbar);

        return () => _pairedSnackbars.Remove(snackbar);
    }

View on GitHub (pinned to 98edec3a0b)

Solutions

  1. Construct the queue on the UI thread.
  2. Use the two-argument constructor and pass an explicit Dispatcher: new SnackbarMessageQueue(duration, Application.Current.Dispatcher).
  3. In tests, establish a Dispatcher (e.g. via a DispatcherSynchronizationContext on a dedicated STA thread) or pass Application.Current.Dispatcher.

Example fix

// before (Task thread has no dispatcher)
var queue = await Task.Run(() => new SnackbarMessageQueue(TimeSpan.FromSeconds(3)));
// after
var queue = new SnackbarMessageQueue(TimeSpan.FromSeconds(3), Application.Current.Dispatcher);
Defensive patterns

Strategy: validation

Validate before calling

Dispatcher? d = Dispatcher.FromThread(Thread.CurrentThread);
var queue = d is not null
    ? new SnackbarMessageQueue(duration)
    : new SnackbarMessageQueue(duration, Application.Current.Dispatcher);

Type guard

Dispatcher.FromThread(Thread.CurrentThread) is not null

Prevention

When it happens

Trigger: Calling new SnackbarMessageQueue(duration) from a Task, thread-pool thread, or unit-test thread that has no WPF dispatcher.

Common situations: DI/async factory constructing the queue; background services; xUnit/nunit test threads; constructing the queue during static initialization off the UI thread.

Related errors


AI-assisted analysis of MaterialDesignInXAML/MaterialDesignInXamlToolkit@98edec3a0b (2026-08-13). Data as JSON: /api/errors/592c22978f3401ea. Report an issue: GitHub.