Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

A Custom WPF Carousel Control

5.00/5 (31 votes)
21 Nov 2019CPOL4 min read 63.3K   3.3K  
This article presents a simple WPF Carousel Control

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:

C#
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:

XAML
<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:

C#
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. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)