{"record":{"id":"aefb117d2e1e3efb","repo":"dotnet/wpf","slug":"sr-calendarcollection","errorCode":null,"errorMessage":"SR.CalendarCollection_MultiThreadedCollectionChangeNotSupported","messagePattern":"SR\\.CalendarCollection_MultiThreadedCollectionChangeNotSupported","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/CalendarBlackoutDatesCollection.cs","lineNumber":158,"sourceCode":"            } while (currentDate != null && ((range = GetContainingDateRange((DateTime)currentDate)) != null));\n\n\n\n            return currentDate;\n        }\n\n        #endregion Public Methods\n\n        #region Protected Methods\n\n        /// <summary>\n        /// All the items in the collection are removed.\n        /// </summary>\n        protected override void ClearItems()\n        {\n            if (!IsValidThread())\n            {\n                throw new NotSupportedException(SR.CalendarCollection_MultiThreadedCollectionChangeNotSupported);\n            }\n\n            foreach (CalendarDateRange item in Items)\n            {\n                UnRegisterItem(item);\n            }\n\n            base.ClearItems();\n            this._owner.UpdateCellItems();\n        }\n\n        /// <summary>\n        /// The item is inserted in the specified place in the collection.\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"item\"></param>\n        protected override void InsertItem(int index, CalendarDateRange item)\n        {","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/CalendarBlackoutDatesCollection.cs#L140-L176","documentation":"CalendarBlackoutDatesCollection (like other WPF calendar collections) enforces single-threaded access via its owning Dispatcher; ClearItems throws NotSupportedException when called from a thread other than the Calendar's UI thread.","triggerScenarios":"Calling BlackoutDates.Clear() from a background/worker thread or Task; modifying the collection inside an async continuation without marshaling back to the dispatcher.","commonSituations":"Loading blackout dates from a database or web service in a background task and clearing/assigning the collection on that thread; async event handlers that forgot Dispatcher.Invoke.","solutions":["Marshal collection mutations back to the UI thread with Dispatcher.Invoke/BeginInvoke","Update the collection in the continuation on the captured UI SynchronizationContext","Compute data off-thread, apply it on the UI thread"],"exampleFix":"// before\nawait LoadBlackoutsAsync();\nblackoutDates.Clear();\n// after\nawait LoadBlackoutsAsync();\nawait dispatcher.InvokeAsync(() => blackoutDates.Clear());","handlingStrategy":"validation","validationCode":"if (!calendar.Dispatcher.CheckAccess())\n{\n    calendar.Dispatcher.Invoke(() => calendar.BlackoutDates.Clear());\n    return;\n}\ncalendar.BlackoutDates.Clear();\n","typeGuard":"bool OnUiThread(Calendar c) => c.Dispatcher.CheckAccess();\n","tryCatchPattern":"try\n{\n    calendar.BlackoutDates.Clear();\n}\ncatch (NotSupportedException)\n{\n    calendar.Dispatcher.Invoke(() => calendar.BlackoutDates.Clear());\n}\n","preventionTips":["Check Dispatcher.CheckAccess before collection mutations","Marshal async results to UI thread","Never touch WPF collections from Task.Run bodies"],"tags":["wpf","threading","collection","not-supported"],"backgroundTag":"unsupported-operation","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}