{"record":{"id":"a7a5e39238a2d820","repo":"dotnet/wpf","slug":"sr-calendarcollection-selecteddatescollection","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/SelectedDatesCollection.cs","lineNumber":133,"sourceCode":"            {\n                this.Add(current);\n            }\n\n            EndAddRange();\n        }\n\n        #endregion Public Methods\n\n        #region Protected methods\n\n        /// <summary>\n        /// Clears all the items of the SelectedDates.\n        /// </summary>\n        protected override void ClearItems()\n        {\n            if (!IsValidThread())\n            {\n                throw new NotSupportedException(SR.CalendarCollection_MultiThreadedCollectionChangeNotSupported);\n            }\n\n            // Turn off highlight\n            this._owner.HoverStart = null;\n\n            ClearInternal(true /*fireChangeNotification*/);\n        }\n\n        /// <summary>\n        /// Inserts the item in the specified position of the SelectedDates collection.\n        /// </summary>\n        /// <param name=\"index\"></param>\n        /// <param name=\"item\"></param>\n        protected override void InsertItem(int index, DateTime item)\n        {\n            if (!IsValidThread())\n            {\n                throw new NotSupportedException(SR.CalendarCollection_MultiThreadedCollectionChangeNotSupported);","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/SelectedDatesCollection.cs#L115-L151","documentation":"SelectedDatesCollection.ClearItems() throws NotSupportedException when IsValidThread() is false, i.e. a collection-change operation is attempted from a thread other than the thread that owns the Calendar (its Dispatcher thread). WPF Calendar collections only allow mutation on their owning thread.","triggerScenarios":"Calling selectedDates.Clear() (or any collection mutation) on the SelectedDatesCollection of a Calendar from a background/worker thread.","commonSituations":"Updating calendar selection from a Task, async callback, or timer thread; deserializing data on a worker thread and pushing results directly into the collection.","solutions":["Marshal the mutation to the UI thread with Dispatcher.Invoke/BeginInvoke.","Use async/await with a captured UI SynchronizationContext so continuations run on the Dispatcher thread.","Bind via a ViewModel ObservableCollection updated on the UI thread instead of touching the Calendar collection directly."],"exampleFix":"// before\ncalendar.SelectedDates.Clear(); // on background thread -> throws\n// after\ncalendar.Dispatcher.Invoke(() => calendar.SelectedDates.Clear());","handlingStrategy":"try-catch","validationCode":"if (!calendar.Dispatcher.CheckAccess())\n{\n    calendar.Dispatcher.Invoke(() => calendar.SelectedDates.Clear());\n    return;\n}\ncalendar.SelectedDates.Clear();","typeGuard":null,"tryCatchPattern":"try\n{\n    calendar.SelectedDates.Clear();\n}\ncatch (NotSupportedException)\n{\n    calendar.Dispatcher.Invoke(() => calendar.SelectedDates.Clear());\n}","preventionTips":["Check Dispatcher.CheckAccess() before mutating any Calendar collection.","Marshal all UI-collection edits through Dispatcher.Invoke.","After awaiting, re-enter the Dispatcher thread before touching the collection."],"tags":["wpf","threading","calendar"],"backgroundTag":"wrong-thread-access","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}