{"record":{"id":"592c22978f3401ea","repo":"MaterialDesignInXAML/MaterialDesignInXamlToolkit","slug":"snackbarmessagequeue-must-be-created-in-a-dispatch","errorCode":null,"errorMessage":"SnackbarMessageQueue must be created in a dispatcher thread","messagePattern":"SnackbarMessageQueue must be created in a dispatcher thread","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/MaterialDesignThemes.Wpf/SnackbarMessageQueue.cs","lineNumber":120,"sourceCode":"            {\n                _waitHandle.Dispose();\n                _isDisposed = true;\n            }\n            _disposedWaitHandle.Set();\n            _disposedWaitHandle.Dispose();\n        }\n    }\n\n    #endregion\n\n    public SnackbarMessageQueue()\n        : this(TimeSpan.FromSeconds(3))\n    {\n    }\n\n    public SnackbarMessageQueue(TimeSpan messageDuration)\n        : this(messageDuration, Dispatcher.FromThread(Thread.CurrentThread)\n                      ?? throw new InvalidOperationException(\"SnackbarMessageQueue must be created in a dispatcher thread\"))\n    { }\n\n    public SnackbarMessageQueue(TimeSpan messageDuration, Dispatcher dispatcher)\n    {\n        _messageDuration = messageDuration;\n        _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));\n    }\n\n    //oh if only I had Disposable.Create in this lib :)  tempted to copy it in like dragablz,\n    //but this is an internal method so no one will know my dirty Action disposer...\n    internal Action Pair(Snackbar snackbar)\n    {\n        if (snackbar is null) throw new ArgumentNullException(nameof(snackbar));\n\n        _pairedSnackbars.Add(snackbar);\n\n        return () => _pairedSnackbars.Remove(snackbar);\n    }","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/98edec3a0b96ef272c587b14bcd67ef5f928a7ed/src/MaterialDesignThemes.Wpf/SnackbarMessageQueue.cs#L102-L138","documentation":"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.","triggerScenarios":"Calling new SnackbarMessageQueue(duration) from a Task, thread-pool thread, or unit-test thread that has no WPF dispatcher.","commonSituations":"DI/async factory constructing the queue; background services; xUnit/nunit test threads; constructing the queue during static initialization off the UI thread.","solutions":["Construct the queue on the UI thread.","Use the two-argument constructor and pass an explicit Dispatcher: new SnackbarMessageQueue(duration, Application.Current.Dispatcher).","In tests, establish a Dispatcher (e.g. via a DispatcherSynchronizationContext on a dedicated STA thread) or pass Application.Current.Dispatcher."],"exampleFix":"// before (Task thread has no dispatcher)\nvar queue = await Task.Run(() => new SnackbarMessageQueue(TimeSpan.FromSeconds(3)));\n// after\nvar queue = new SnackbarMessageQueue(TimeSpan.FromSeconds(3), Application.Current.Dispatcher);","handlingStrategy":"validation","validationCode":"Dispatcher? d = Dispatcher.FromThread(Thread.CurrentThread);\nvar queue = d is not null\n    ? new SnackbarMessageQueue(duration)\n    : new SnackbarMessageQueue(duration, Application.Current.Dispatcher);","typeGuard":"Dispatcher.FromThread(Thread.CurrentThread) is not null","tryCatchPattern":null,"preventionTips":["Prefer the two-argument constructor with an explicit Dispatcher.","Construct the queue on the UI thread, never inside Task.Run.","In tests, establish a Dispatcher before creating the queue."],"tags":["wpf","snackbar","threading","dispatcher","invalid-operation"],"backgroundTag":null,"analyzedSha":"98edec3a0b96ef272c587b14bcd67ef5f928a7ed","analyzedAt":"2026-08-13T14:31:19.111Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}