Introduction
A carousel control is a powerful and visually appealing way to present multiple items of data. Unfortunately, Microsoft does not provide a stock implementation. There are many freely available carousel controls available.
The two best known freeware carousel controls are arguably the following:
Initially, I tried using the first version, and adapting it to our own needs. Unfortunately, it is based on the Microsoft PathListBox
control thereby hiding most of the implementation details. I found it rather difficult to modify it to suit our needs and eventually gave up.
The second carousel is a nice simple implementation, but the author has hard coded spheres as the carousel items, and he has not exposed any dependency properties which limits its usefulness.
I decided to use the second carousel as a starting point to create a more flexible carousel control.
This article includes the source code for the new WPF carousel control, and a simple demonstration application.
Background
You will need a good understanding of C# and a basic understanding of WPF.
Overview
The carousel control can arrange items horizontally:
It can also arrange the items vertically:
The new carousel control, which I have called WPFCarouselControl
(no marks for originality, I fear) has the following dependency properties:
ItemsSource
| The data displayed by the carousel items. |
SelectedItem | The currently selected item. |
CarouselItemTemplate | Defines the appearance and behaviour of each carousel item. |
AutoSizeToParent | If true , the control sizes itself to fit the available space. |
TiltInDegrees | The tilt of the axis about which the items appear to rotate. |
RotationSpeed | The speed at which the items rotate when a new item is selected. |
Fade | A value between 0 and 1 which determines how the opacity of items varies with position. Those furthest from the selected item have the lowest opacity. |
Scale | A scaling that is applied to the items in the carousel to create a 3D effect. A value of one means that all items have the same size. A value less than one creates perspective. The range is 0 to 1 inclusive. |
VerticalOrientation | If true items are arranged vertically, if false items are arranged horizontally. |
Using the WPFCarouselControl
It is straightforward to use the control in an application.
First, create a class which stores the data displayed in one carousel item. For example:
public class RadioStation
{
public string Name { get; set; }
public string ShortName { get; set; }
public string ImageSource { get; set; }
public string Text { get; set; }
}
Next, add a CarouselControl
to your view. For example:
<WPFCarouselControl:CarouselControl Grid.Row="5" Grid.Column="1"
Grid.ColumnSpan="5" x:Name="_carouselDABRadioStations"
ItemsSource="{Binding RadioStationsDAB}"
SelectedItem="{Binding SelectedRadioStationDAB,Mode=TwoWay}"
ShowRotation="True" TiltInDegrees="10"
AutoSizeToParent="true" RotationSpeed="100"
VerticalOrientation="False" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<WPFCarouselControl:CarouselControl.Style>
<Style TargetType="WPFCarouselControl:CarouselControl">
<Setter Property="CarouselItemTemplate" >
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="1"
BorderBrush="Gainsboro" Background="SteelBlue"
Width="250" Height="150">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
BorderThickness="0" Background="White">
<Image Grid.Row="0"
Source="{Binding ImageSource}"
VerticalAlignment="Center"
HorizontalAlignment="Center" Height="100"/>
</Border>
<Label Grid.Row="1"
Content="{Binding ShortName}"
Foreground="White" Background="Transparent"
FontSize="20" FontFamily="Arial"
Style="{StaticResource labelStyleCentred}"
DockPanel.Dock="Bottom" Height="Auto"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</WPFCarouselControl:CarouselControl.Style>
</WPFCarouselControl:CarouselControl>
Note the CarouselItemTemplate
property which defines a carousel item consisting of a rectangle containing an image above a line of text.
The ItemsSource
property is bound to the RadioStationsDAB
property defined in the view model as follows:
private System.Collections.ObjectModel.ObservableCollection
<Model.RadioStation> _radioStationsDAB;
public System.Collections.ObjectModel.ObservableCollection
<Model.RadioStation> RadioStationsDAB
{
get
{
return _radioStationsDAB;
}
set
{
_radioStationsDAB = value;
NotifyPropertyChanged("RadioStationsDAB");
}
}
Implementation Details
The WPF carousel control is a WPF user control containing a Canvas
control.
The item controls are child elements of the canvas
, laid out on a circle projected onto the plane of the screen.
The control implements a SelectionChanged
event allowing the owner to receive a notification when an item is selected by means of a left mouse button click.
The rotation is implemented using a timer which is started when the selected item changes. The timer fires every 10 milliseconds to ensure a smooth rotation. On each tick, it moves the items by an amount proportional to the rotation speed.
Adding/Removing Items
The ItemsSource
property assumes that it is bound to a collection object that implements the System.Collections.IEnumerable
and System.Collections.Specialized.INotifyCollectionChanged
interfaces. The latter interface must be implemented if items are added and/or removed from the items list.
Limitations
The current control lays out the items uniformly around an imaginary circle. If you wish to change the layout, you will need to edit the SetElementPositions
method. If you are feeling adventurous, you could layout the items along a Path
dependency property.
History
- 9th May, 2019: Version 1
- 9th May, 2019: Version 2: Implemented the
CarouselItemTemplate
dependency property - 5th November, 2019: Version 3: Fixed a bug with the rotation algorithm that caused the direction of rotation to reverse unexpectedly. The download code has been updated.
- 21st November, 2019: Version 4: Updated the
ItemsSource
property to allow the adding and/or removing of items. - 22nd November, 2019: Version 5: Fixed the layout so that the selected item is now always centred.