Carousel
A 3D carousel: the items stand round a circle in perspective, and the selected one turns to face the viewer at the front, the others angled away behind it.
public partial class Carousel : ItemsControl
Inherits from / implements: ItemsControl
Remarks
Use it to browse a modest set of visual items one at a time – product photographs, album or
book covers, a portfolio, the screens of a kiosk, the templates in a "new document" gallery. It is
an ItemsControl, so the items can be anything: bind
ItemsControl.ItemsSource to your data and describe each item with an
ItemsControl.ItemTemplate, or add elements to ItemsControl.Items
directly.
Selection and navigation
SelectedIndex is the item at the front. Set it, or bind it, to a valid index –
it starts at -1, where no item has been brought forward and the items are not yet arranged
round the circle. The user moves the selection by clicking an item, turning the mouse wheel, or
pressing the Left and Right arrow keys (the MoveToLeft and MoveToRight
commands, which buttons of your own can use too). Each move turns the carousel in half a second, and
SelectedIndexChanged follows.
Items
Each item is drawn at ItemDimension – 300 by 250 logical pixels by default – and
then shown in 3D, so that size decides its shape and how sharp it is rather than how large it
appears. For a list of image paths, the template keyed
CarouselControlResources.CarouselItemTemplateKey shows each picture in
a white frame. IsReflectionRenderingEnabled adds a mirror-image reflection beneath
every item.
Shape of the ring
GapBetweenItems spaces the items round the circle, and with it the circle's
size; ItemRenderAngle turns the items that are not at the front;
DistanceFromCentreToUser brings the front item towards the viewer, and
GapBetweenCurrentDisplayFrontItemAndOthers pushes the rest back. The view is set by
Camera (or CarouselViewport3DCamera) and lit by
CarouselViewport3DAmbientLightColor. All lengths in 3D are in model units, in which an
item is one unit tall.
Examples
A product gallery in XAML: the window's data context exposes ProductImages, a list of
image paths, and CurrentProduct, the index of the product on show.
<Window x:Class="Shop.GalleryWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:car="clr-namespace:Binarymission.WPF.Controls.Containers;assembly=Binarymission.WPF.Controls.Carousel"
xmlns:carRes="clr-namespace:Binarymission.WPF.Controls.Containers.SharedResources;assembly=Binarymission.WPF.Controls.Carousel"
Title="Spring collection" Width="900" Height="520">
<DockPanel Background="#20242B">
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" Margin="12">
<Button Content="Previous" Margin="4" Command="{x:Static car:Carousel.MoveToLeft}" CommandTarget="{Binding ElementName=Gallery}" />
<Button Content="Next" Margin="4" Command="{x:Static car:Carousel.MoveToRight}" CommandTarget="{Binding ElementName=Gallery}" />
</StackPanel>
<car:Carousel x:Name="Gallery"
ItemsSource="{Binding ProductImages}"
SelectedIndex="{Binding CurrentProduct}"
ItemTemplate="{DynamicResource {x:Static carRes:CarouselControlResources.CarouselItemTemplateKey}}"
ItemDimension="320,240"
IsReflectionRenderingEnabled="True"
ItemRenderAngle="40"
GapBetweenItems="0.6" />
</DockPanel>
</Window>The same carousel filled with elements from code, reacting as the user turns it.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using Binarymission.WPF.Controls.Containers;
Carousel gallery = new Carousel
{
ItemDimension = new Size(320, 240),
IsReflectionRenderingEnabled = true
};
foreach (string file in new[] { "chair.jpg", "desk.jpg", "lamp.jpg", "shelf.jpg", "sofa.jpg" })
{
gallery.Items.Add(new Image { Source = new BitmapImage(new Uri("pack://application:,,,/Products/" + file)), Stretch = System.Windows.Media.Stretch.Uniform });
}
gallery.SelectedIndex = 0;
gallery.SelectedIndexChanged += (sender, e) =>
statusText.Text = "Product " + (gallery.SelectedIndex + 1) + " of " + gallery.Items.Count;See also
Members at a glance
| Constructors | |
|---|---|
Carousel | Creates an empty carousel, with the arrow-key commands ready and white lighting. |
| Properties | |
Camera | Gets or sets the perspective camera the carousel is viewed through, to change the viewpoint, the distance or the field of view. |
CarouselViewport3DAmbientLightColor | Gets or sets the colour of the light the carousel's items are lit by. |
CarouselViewport3DCamera | Gets or sets the camera the carousel is viewed through, of any kind – for example an
OrthographicCamera for a flat view without perspective. |
DistanceFromCentreToUser | Gets or sets how far the item at the front is brought forward, towards the viewer. |
GapBetweenCurrentDisplayFrontItemAndOthers | Gets or sets how far the items that are not at the front are pushed back, away from the viewer. |
GapBetweenItems | Gets or sets how far apart the items stand round the circle, which also sets the circle's size. |
IsReflectionRenderingEnabled | Gets or sets whether each item is drawn with a mirror-image reflection beneath it, fading to transparent, as though standing on a glossy floor. |
ItemDimension | Gets or sets the size each item is drawn at before it is placed in 3D, which decides its shape and its sharpness. |
ItemRenderAngle | Gets or sets how far the items that are not at the front are turned away from the viewer. |
SelectedIndex | Gets or sets the position of the item at the front of the carousel, facing the viewer. |
VisualChildrenCount | Gets the number of visual children: one once the template has been applied, otherwise none. |
| Methods | |
ClearContainerForItemOverride | Takes an item off the carousel when it is removed, and brings the selection back within the remaining items. |
OnApplyTemplate | Finds the 3D viewport, the item container and the light in the template, and applies the camera and the light colour to them. |
OnMouseWheel | Turns the carousel one item for each notch of the mouse wheel, and gives it keyboard focus. |
PrepareContainerForItemOverride | Sizes an item's container to ItemDimension and puts the item on the carousel. |
| Events | |
SelectedIndexChanged | Occurs when SelectedIndex changes, whether the user turned the carousel or code set
the index. |
| Fields | |
CameraProperty | Identifies the Camera dependency property. |
CarouselViewport3DAmbientLightColorProperty | Identifies the CarouselViewport3DAmbientLightColor dependency property. |
CarouselViewport3DCameraProperty | Identifies the CarouselViewport3DCamera dependency property. |
DistanceFromCentreToUserProperty | Identifies the DistanceFromCentreToUser dependency property. |
GapBetweenCurrentDisplayFrontItemAndOthersProperty | Identifies the GapBetweenCurrentDisplayFrontItemAndOthers dependency property. |
GapBetweenItemsProperty | Identifies the GapBetweenItems dependency property. |
IsReflectionRenderingEnabledProperty | Identifies the IsReflectionRenderingEnabled dependency property. |
ItemDimensionProperty | Identifies the ItemDimension dependency property. |
ItemRenderAngleProperty | Identifies the ItemRenderAngle dependency property. |
MoveToLeft | The command that moves the selection to the previous item; bound to the Left arrow key. |
MoveToRight | The command that moves the selection to the next item; bound to the Right arrow key. |
SelectedIndexProperty | Identifies the SelectedIndex dependency property. |
Constructors
Carousel
Creates an empty carousel, with the arrow-key commands ready and white lighting.
Remarks
Add items, then set SelectedIndex to bring one to the front.
Properties
Camera
Gets or sets the perspective camera the carousel is viewed through, to change the viewpoint, the distance or the field of view.
- Value
- The default is
null, which uses the carousel's own camera: at (0, 1, 6), looking towards the centre of the carousel with a 60-degree field of view.
Remarks
Move the camera nearer (a smaller Z) to make the carousel larger, raise it (a larger Y) to
look down on the ring, or narrow the PerspectiveCamera.FieldOfView to flatten the
perspective. CarouselViewport3DCamera, if set, takes precedence when the template is
applied.
Example
<car:Carousel.Camera>
<PerspectiveCamera Position="0,2,5" LookDirection="0,-2,-5" UpDirection="0,1,0" FieldOfView="50" />
</car:Carousel.Camera>See also
CarouselViewport3DAmbientLightColor
Gets or sets the colour of the light the carousel's items are lit by.
- Value
- The default is
Colors.White: every item is shown in its own colours.
Remarks
The light is even and comes from everywhere, so it tints and darkens every item alike: a
grey light dims the carousel, a warm one gives it a cast. It does not light the
Control.Background.
CarouselViewport3DCamera
Gets or sets the camera the carousel is viewed through, of any kind – for example an
OrthographicCamera for a flat view without perspective.
- Value
- The default is
null: the carousel usesCamera, or its own camera when that isnullas well.
Remarks
When both this and Camera are set, this one is used when the template is
applied; after that, the one set most recently is in effect. Setting either back to
null leaves the camera in use unchanged.
See also
DistanceFromCentreToUser
Gets or sets how far the item at the front is brought forward, towards the viewer.
- Value
- A distance in model units, where an item is one unit tall, added to the circle's radius. The
default is
1.
Remarks
A larger value makes the front item appear larger, as it comes closer to the camera; too
large and it passes the camera and disappears. To make the whole carousel larger or smaller, move
the Camera instead.
See also
GapBetweenCurrentDisplayFrontItemAndOthers
Gets or sets how far the items that are not at the front are pushed back, away from the viewer.
- Value
- A distance in model units, where an item is one unit tall. The default is
0.65.
Remarks
A larger gap sets the front item further apart from the rest, so it stands out more; 0
leaves every item on the circle itself.
See also
GapBetweenItems
Gets or sets how far apart the items stand round the circle, which also sets the circle's size.
- Value
- The distance from one item to the next round the circle, in model units, where an item is
one unit tall. The default is
0.25.
Remarks
The circle's circumference is this distance times the number of items, so the ring grows as items are added. Small values overlap the items behind the front one like a fanned deck; values around the width of an item spread them out side by side.
See also
IsReflectionRenderingEnabled
Gets or sets whether each item is drawn with a mirror-image reflection beneath it, fading to transparent, as though standing on a glossy floor.
- Value
trueto draw reflections. The default isfalse.
Remarks
The carousel draws the reflection itself, so it works for any item and any item template.
Reflections suit a dark Control.Background.
Changing the property rebuilds every item. If the carousel has no
ItemsControl.ItemTemplate of its own, or has the template keyed
CarouselControlResources.CarouselItemReflectionEnabledTemplateKey, it
is given the template keyed CarouselControlResources.CarouselItemTemplateKey
at the same time; a template of your own is left alone.
ItemDimension
Gets or sets the size each item is drawn at before it is placed in 3D, which decides its shape and its sharpness.
- Value
- A size in logical pixels (1/96 inch). The default is 300 by 250. A size with a width or height of zero or less is read as the default.
Remarks
Each item is laid out at this size, as though in a window of its own, and the picture is then put on a panel one unit tall in 3D. So the ratio of width to height is the shape of every panel, and the size itself is the resolution: larger sizes stay sharp when the item is close to the camera. How large an item appears on screen is set by the camera and the carousel's own size, not by this.
Changing it rebuilds every item.
Example
<!-- Portrait book covers. -->
<car:Carousel ItemDimension="200,300" />ItemRenderAngle
Gets or sets how far the items that are not at the front are turned away from the viewer.
- Value
- An angle in degrees, turning each item about its vertical axis. The default is
45.
Remarks
The front item always faces the viewer squarely. 0 leaves every item facing
forwards, so the ring looks flat; values towards 90 show the others edge-on, so they almost
disappear. The carousel turns to the new angle at once.
See also
SelectedIndex
Gets or sets the position of the item at the front of the carousel, facing the viewer.
- Value
- The zero-based position of the item in
ItemsControl.Items. The default is-1: no item is at the front, and the items are not yet arranged round the circle.
Remarks
Setting it turns the carousel to bring that item forward, over half a second, and raises
SelectedIndexChanged. It binds two-way by default, so a view model sees the user's
choice. A value set before the control is loaded is applied once it is; a value outside the items
is ignored and the carousel does not move.
When items are removed and the index falls past the last item, it moves to the last item.
Example
// Show the last product added.
gallery.SelectedIndex = gallery.Items.Count - 1;See also
VisualChildrenCount
Gets the number of visual children: one once the template has been applied, otherwise none.
Methods
ClearContainerForItemOverride
Takes an item off the carousel when it is removed, and brings the selection back within the remaining items.
Parameters
element- The container that held the item.
item- The item being removed.
Remarks
Call the base method when overriding, so the item's 3D panel is removed with it.
OnApplyTemplate
Finds the 3D viewport, the item container and the light in the template, and applies the camera and the light colour to them.
Remarks
A custom template provides a Viewport3D named PART_CarouselViewPort, a
ContainerUIElement3D inside it named PART_CarouselItemContainer, an
AmbientLight named viewport3DAmbientLight, and a hidden panel with
IsItemsHost="True" for the item containers. Any of them may be left out; the features that
need it then do nothing.
The camera applied is CarouselViewport3DCamera if set, otherwise
Camera, otherwise the carousel's own.
OnMouseWheel
Turns the carousel one item for each notch of the mouse wheel, and gives it keyboard focus.
Parameters
e- The wheel movement. Turning the wheel away from the user moves to the next item; towards the user, to the previous one.
Remarks
The event is marked handled only when the carousel actually moved, so at either end of the carousel the wheel goes on to scroll whatever contains it.
PrepareContainerForItemOverride
Sizes an item's container to ItemDimension and puts the item on the carousel.
Parameters
element- The container for the item, or the item itself when it is an element.
item- The item.
Remarks
Call the base method first when overriding, or the item does not appear.
Events
SelectedIndexChanged
Occurs when SelectedIndex changes, whether the user turned the carousel or code set
the index.
Remarks
Raised as the carousel starts turning, with the new index already in
SelectedIndex. Not raised for changes made before the control is loaded. A value set
outside the items still raises it, although the carousel does not move.
Example
gallery.SelectedIndexChanged += (sender, e) =>
{
Product product = (Product)gallery.Items[gallery.SelectedIndex];
priceText.Text = product.Price.ToString("C");
};Fields
CameraProperty static
Identifies the Camera dependency property.
CarouselViewport3DAmbientLightColorProperty static
Identifies the CarouselViewport3DAmbientLightColor dependency property.
CarouselViewport3DCameraProperty static
Identifies the CarouselViewport3DCamera dependency property.
DistanceFromCentreToUserProperty static
Identifies the DistanceFromCentreToUser dependency property.
GapBetweenCurrentDisplayFrontItemAndOthersProperty static
Identifies the GapBetweenCurrentDisplayFrontItemAndOthers dependency property.
GapBetweenItemsProperty static
Identifies the GapBetweenItems dependency property.
IsReflectionRenderingEnabledProperty static
Identifies the IsReflectionRenderingEnabled dependency property.
ItemDimensionProperty static
Identifies the ItemDimension dependency property.
ItemRenderAngleProperty static
Identifies the ItemRenderAngle dependency property.
MoveToLeft static
The command that moves the selection to the previous item; bound to the Left arrow key.
Remarks
Disabled while the first item (or no item) is selected, so a button using it greys out at the
start of the carousel. Give a button the command and the carousel as its
CommandTarget, or let it find the carousel through
keyboard focus.
The Left arrow key works whenever the carousel has keyboard focus, which it takes when the user clicks it or turns the mouse wheel over it.
Example
<Button Content="Previous" Command="{x:Static car:Carousel.MoveToLeft}" CommandTarget="{Binding ElementName=Gallery}" />See also
MoveToRight static
The command that moves the selection to the next item; bound to the Right arrow key.
Remarks
Disabled while the last item is selected, so a button using it greys out at the end of the
carousel. See MoveToLeft for how to use it.
See also
SelectedIndexProperty static
Identifies the SelectedIndex dependency property.