DateRangePicker
Overview
Section titled “Overview”DateRangePicker composes the same trigger + NaviusAnchoredPopup + NaviusCalendar anatomy as
NaviusDatePicker (its NaviusDatePickerBase parent), adding a two-pick commit model on top: the
first day picked sets Start, the second sets End (ordered via DateRangeCommitEngine) and closes
the popup; Escape reverts both endpoints to their state when the popup opened. The calendar runs in
CalendarSelectionMode.SingleRange purely so Start/End/middle days render as selected; commits
never go through the native mode’s Shift-to-extend semantics.
xmlns:dateRangePicker="clr-namespace:Navius.Wpf.Primitives.Controls.DateRangePicker;assembly=Navius.Wpf.Primitives"
<dateRangePicker:NaviusDateRangePicker Value="{Binding StayDates, Mode=TwoWay}" Placeholder="Select dates" />Properties
Section titled “Properties”| Property | Type | Default | From | Description |
|---|---|---|---|---|
Value |
NaviusDateRange |
NaviusDateRange.Empty |
NaviusDateRangePicker |
Two-way bindable by default. Either endpoint may be null mid-pick. |
IsOpen |
bool |
false |
NaviusDatePickerBase |
Two-way bindable; also settable via Enter/Space/ArrowDown when closed. |
Placeholder |
string? |
null |
NaviusDatePickerBase |
Muted trigger text shown while Value.IsEmpty. |
Side |
PlacementSide |
Bottom |
NaviusDatePickerBase |
Popup placement side. |
Align |
PlacementAlign |
Start |
NaviusDatePickerBase |
Popup placement alignment (matches the web contract’s NaviusDateRangePickerContent default Align="start"). |
SideOffset |
double |
6 |
NaviusDatePickerBase |
|
AlignOffset |
double |
0 |
NaviusDatePickerBase |
|
DisplayText |
string? |
null |
NaviusDatePickerBase |
Read-only. The formatted trigger label ("start - end", "start - " while the second pick is pending, or the placeholder). |
HasSelection |
bool |
false |
NaviusDatePickerBase |
Read-only. Drives placeholder-muting trigger styling. |
Events
Section titled “Events”| Event | Signature | Fires when |
|---|---|---|
ValueChanged |
RoutedEventHandler |
On every committed endpoint change: first pick, second pick, and an Escape revert that actually changed the value. |
Keyboard interactions
Section titled “Keyboard interactions”| Key | Behavior |
|---|---|
Enter / Space / ArrowDown (trigger, popup closed) |
Opens the popup (inherited from NaviusDatePickerBase). |
Escape (popup open) |
Reverts both endpoints to the value captured when the popup opened, then closes. |
Enter / Space (a focused calendar day) |
Commits that day as the next pick: first pick fills Start, second fills End and closes. |
Arrow keys / PageUp / PageDown / Home / End (inside the calendar) |
Native System.Windows.Controls.Calendar day-grid navigation; does not commit a pick. |
| Outside press | Dismisses the popup without reverting whatever was already committed. |
Per the M6 audit, only the open-when-closed keys, Escape, and the pick-commit engine are actually
unit-tested; native Calendar’s own in-grid navigation and outside-press dismissal are exercised as
inherited platform behavior, not independently driven by a test.
UIA mechanism
Section titled “UIA mechanism”NaviusDateRangePickerAutomationPeer (a FrameworkElementAutomationPeer) reports
AutomationControlType.Custom with localized control type "date range picker" (the native
DatePickerAutomationPeer shape), plus a read-only IValueProvider surfacing "start - end" (or
"start - " mid-pick, or empty while unset, never the placeholder) and IExpandCollapseProvider
over IsOpen. The web contract’s popup role="dialog" has no direct equivalent; ExpandCollapse
plus focus moved into the calendar on open is the native WPF idiom instead. Verified by
automation-peer round-trip assertions in DateRangePickerTests.cs, plus the M6-audit-added
OnOpened_WithRealCalendarPart_SwitchesToSingleRangeAndSyncsSelectionWithoutThrowing, which applies
a real template first (prior tests never called ApplyTemplate(), so CalendarPart stayed null
and the SingleRange switch/selection repaint were never actually exercised against a real native
Calendar).
Web deltas
Section titled “Web deltas”- The two endpoint segmented
NaviusDateInputs, the hidden bubble inputs, therole="group"control wrapper, and theGranularity/MinValue/MaxValuepassthroughs are not ported in this wave (the DateInput family is a concurrent, separately-owned port). The trigger instead shows a plain read-only"start - end"display formatted perCultureInfo.CurrentCulture; composing editable endpoint fields into the trigger is a follow-up. ZitsCalendar(a styled-layer component with no source inNavius.Primitivesat all) is replaced byNaviusCalendar, a Tier A control derivingSystem.Windows.Controls.Calendarand inheriting its native keyboard model andCalendarAutomationPeerfor free, re-templated to tokens.- The web’s Popover Portal/Positioner/Popup composition is replaced by
NaviusAnchoredPopupdirectly:Side/Align/SideOffset/AlignOffsetare flat properties on the picker root rather than a separate Positioner part. NaviusDateRangeis areadonly record structoverDateTime?(notDateOnly, to matchSystem.Windows.Controls.Calendar’s own value type); the web contract’sOrdered()helper is unnecessary becauseDateRangeCommitEnginealways orders on commit, so a typed-backwards range can never occur here (unlike the web, where typing a start date after an end date via the segmented inputs is not auto-normalized, moot in this port since no endpoint inputs exist yet).- Known residual: no validation logic exists for cross-endpoint constraints, and no endpoint-level
MinValue/MaxValueconstraints are ported in this wave at all (see the passthroughs bullet above). - Doc-only correction (M6 audit):
Themes/DateRangePicker.xaml(andCalendar.xaml/DatePicker.xaml) previously claimed to NOT be merged intoGeneric.xaml, “same precedent as Select.xaml”; both halves of that claim were false (all three, plusSelect.xaml, are merged intoGeneric.xaml). No functional impact, comment-accuracy only.
Captures
Section titled “Captures”The DateRangePicker Gallery page rendered at the pinned commit, in each theme.



The family’s sibling Gallery pages:





