dotnet/wpf · error · InvalidOperationException
SR.Calendar_CheckSelectionMode_InvalidOperation
Error message
SR.Calendar_CheckSelectionMode_InvalidOperation
What it means
SelectedDatesCollection.CheckSelectionMode validates that the Calendar's SelectionMode permits programmatic modification of the SelectedDates collection. When SelectionMode is SingleDate and the collection already contains dates, any Add/insert into SelectedDates throws this InvalidOperationException because a SingleDate calendar can only hold one selected date, which must be set via the SelectedDate property instead.
Solutions
- Set Calendar.SelectionMode to MultipleRange or SingleRange before adding multiple dates to SelectedDates.
- For a single-date selection, set the SelectedDate property instead of calling SelectedDates.Add.
- Clear SelectedDates first, or guard the Add with a check of SelectionMode and Count.
- Call AddRange only when SelectionMode allows ranges (SingleRange/MultipleRange).
Example fix
// before
calendar.SelectedDates.Add(new DateTime(2026, 5, 1));
// after
if (calendar.SelectionMode == CalendarSelectionMode.SingleDate)
calendar.SelectedDate = new DateTime(2026, 5, 1);
else
calendar.SelectedDates.Add(new DateTime(2026, 5, 1)); Defensive patterns
Strategy: validation
Validate before calling
if (calendar.SelectionMode == CalendarSelectionMode.SingleDate && calendar.SelectedDates.Count > 0)
throw new InvalidOperationException("Use SelectedDate or change SelectionMode before adding dates."); Type guard
bool canAddMultiple = calendar.SelectionMode == CalendarSelectionMode.MultipleRange || calendar.SelectionMode == CalendarSelectionMode.SingleRange;
Prevention
- Set SelectionMode before manipulating SelectedDates.
- Use SelectedDate for single-date calendars.
- Never hardcode SelectedDates.Add without checking SelectionMode.
- Prefer SelectRange only on range-capable modes.
When it happens
Trigger: Calling SelectedDates.Add(date) (or InsertItem via collection initializer / AddRange) while Calendar.SelectionMode == CalendarSelectionMode.SingleDate and SelectedDates.Count > 0; e.g. adding a second date to the collection without changing SelectionMode.
Common situations: Developers defaulting SelectionMode to SingleDate (the default) then trying to pre-select multiple dates or add dates programmatically in code; porting code written for MultipleRange/SingleRange calendars to a SingleDate calendar.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- SR.Calendar_OnSelectedDateChanged_InvalidOperation
- Animation_Invalid_DefaultValue
- Cannot remove signature from read-only file.
- Image_EncoderNoColorContext
- Image_EncoderNoGlobalMetadata
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/c67ec32a174d3642.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/SelectedDatesCollection.cs:451
Debug.Assert(_isAddingRange);
_isAddingRange = false;
RaiseSelectionChanged(this._removedItems, this._addedItems);
this._removedItems.Clear();
this._addedItems.Clear();
this._owner.UpdateCellItems();
}
private bool CheckSelectionMode()
{
if (this._owner.SelectionMode == CalendarSelectionMode.None)
{
throw new InvalidOperationException(SR.Calendar_OnSelectedDateChanged_InvalidOperation);
}
if (this._owner.SelectionMode == CalendarSelectionMode.SingleDate && this.Count > 0)
{
throw new InvalidOperationException(SR.Calendar_CheckSelectionMode_InvalidOperation);
}
// if user tries to add an item into the SelectedDates in SingleRange mode, we throw away the old range and replace it with the new one
// in order to provide the removed items without an additional event, we are calling ClearInternal
if (this._owner.SelectionMode == CalendarSelectionMode.SingleRange && !_isAddingRange && this.Count > 0)
{
this.ClearInternal();
return true;
}
else
{
return false;
}
}
private bool IsValidThread()
{
return Thread.CurrentThread == this._dispatcherThread;View on GitHub (pinned to 81131a70a4)