Skip to content

Carousel

Carousel is an item host with prev/next chevrons, dot indicators, and ArrowLeft/ArrowRight keyboard navigation. It derives Selector directly (the same WPF base ListBox/TabControl use) rather than a bespoke “current index” property, so it gets SelectedIndex/SelectedItem as bindable dependency properties for free; the template’s ItemContainerStyle uses Selector.IsSelected to show only the current slide, cross-faded, and to light the matching dot. Slides are added directly as UIElement items (each item is its own container). Pointer-swipe physics are explicitly out of scope; only the chevrons, dots, and keyboard arrows drive navigation.

xmlns:carousel="clr-namespace:Navius.Wpf.Ui.Carousel;assembly=Navius.Wpf.Ui"
<carousel:NaviusCarousel Height="160">
<Border Background="{DynamicResource Navius.Muted}">
<TextBlock Text="Slide 1" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<Border Background="{DynamicResource Navius.Muted}">
<TextBlock Text="Slide 2" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</carousel:NaviusCarousel>
Property Type Default From Description
Loop bool true NaviusCarousel Whether Next from the last slide wraps to the first (and Previous from the first wraps to the last).
Items ItemCollection empty ItemsControl (via Selector) Populated directly with UIElement slides; each item is its own container (IsItemItsOwnContainerOverride returns true for UIElement).
SelectedIndex int -1 Selector Bindable current-slide index. Auto-initializes to 0 the first time items appear (an empty carousel with slides and nothing selected would read as broken).
Command Description
NaviusCarousel.PreviousCommand Moves to the previous slide (wraps if Loop). Bound to the template’s left chevron button.
NaviusCarousel.NextCommand Moves to the next slide (wraps if Loop). Bound to the template’s right chevron button.
NaviusCarousel.GoToSlideCommand Selects the slide at the int index passed as the command parameter. Bound to each dot indicator, parameterized via its ItemsControl.AlternationIndex.
Key Behavior
Left Arrow Moves to the previous slide (wraps if Loop).
Right Arrow Moves to the next slide (wraps if Loop).

NaviusCarousel does not override OnCreateAutomationPeer, and Selector itself does not supply one either (only concrete selector controls like ListBox do), so the control falls back to ItemsControl’s peer, ItemsControlAutomationPeer, reporting AutomationControlType.List. The unit suite exercises CarouselEngine.MoveIndex (the pure index-wrap math backing both Loop directions and the no-loop clamp), default Loop/SelectedIndex values, auto-selection of the first slide once items are added, and GoToSlideCommand selection (tests/Navius.Wpf.Tests/UiCompositeTests.cs).

  • Pointer-swipe physics are explicitly out of scope for this control; only the chevrons, dots, and keyboard arrows drive navigation, unlike touch/pointer-swipe carousels on the web.
  • Known residual (M6 audit): the slide crossfade storyboards (two 0.15s opacity DoubleAnimations in the container’s EnterActions/ExitActions) have no reduced-motion guard. Gating them would require adding a new ShouldAnimate dependency property and rewiring the triggers, which the audit judged to exceed a surgical fix; the fade is a one-shot 150ms crossfade rather than one of the endless loops the ReducedMotion seam targets, and no doc comment claims otherwise. Recorded for a follow-up if the discipline is tightened to cover transient transitions.