×
Namespaces

Variants
Actions

How to create a simple image carousel using basic Windows Phone controls

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to create a button-driven image carousel using basic Windows Phone UI controls from the SDK.

WP Metro Icon UI.png
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0 SDK
Devices(s): Nokia Lumia 925
Compatibility
Platform(s):
Windows Phone 8
Article
Created: Depechie (02 Dec 2013)
Last edited: Depechie (10 Dec 2013)

Contents

Introduction

A common problem when a page has pictures and text is that it is difficult to display both at the same time. One approach to this problem is to use a "carousel" for display of the images - the user can then see that there are multiple images, and scroll between them, but is still able to see the text.

This article shows how to create a simple button-driven carousel using only the basic Windows Phone controls that are available in the SDK.

Note.pngNote: The solution does not provide gesture support - image navigation is done using buttons. For ideas on how to add support for gestures, take a look at my blog post on how to mimic the facebook settings pane here

Implementation

Create the initial page

Create a new windows phone app, rename the MainPage.xaml to CarouselPoor.xaml and change the ContentPanel into the one given below. The page contains a ScrollViewer that will act as our carousel! It will only scroll horizontally and contains a StackPanel which hosts our images.

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
 
<ScrollViewer x:Name="ImageCarousel"
Grid.Row="0"
ManipulationMode="Control"
IsHitTestVisible="False"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled"
>
<StackPanel x:Name="ImageList" Orientation="Horizontal" />
</ScrollViewer>
<controls:Indicator x:Name="Indicator"
Grid.Row="1"
VerticalAlignment="Top"
HorizontalAlignment="Right"
ItemsCount="5"
Margin="0,6,12,0"
/>
 
<Button Content="&lt;" x:Name="ButtonLeft"
Grid.Row="0"
FontSize="30"
FontWeight="Bold" Background="LightGray" Foreground="DarkSlateGray"
BorderThickness="0" Margin="0" Padding="0" Height="70" Width="70"
HorizontalAlignment="Left" VerticalContentAlignment="Top"
Opacity="0.75" Click="ButtonLeft_Click"
/>
 
<Button Content="&gt;" x:Name="ButtonRight"
Grid.Row="0"
FontSize="30"
FontWeight="Bold" Background="LightGray" Foreground="DarkSlateGray"
BorderThickness="0" Margin="0" Padding="0" Height="70" Width="70"
HorizontalAlignment="Right" VerticalContentAlignment="Top"
Opacity="0.75" Click="ButtonRight_Click"
/>
 
<RichTextBox Grid.Row="2" VerticalAlignment="Top" Margin="12,6,12,0">
<Paragraph>
<Run FontSize="28">
What is Cats in Sinks?
</Run>
<LineBreak />
<LineBreak />
<Run>
It's obvious. It's about cats. And kittens. Who like sinks. And basins.
</Run>
</Paragraph>
</RichTextBox>
</Grid>

There are also 2 buttons defined, these will be used to trigger the actual navigation.

The page also contains a control called Indicator which shows how many images there are in the carousel and highlights the currently active image. The code for this control is available in the project and is not further explained in this article. The only thing you need to know is that it has a property ItemsCount that needs to be set equal to the amount of images shown in the carousel.

You also need to change the SelectedPivotIndex to indicate what image is currently active/shown to the user, so that the corresponding square is highlighted on the screen.

Loading and navigating the images

Now that the page layout has been set, we need to fill the carousel with actual images. All this is done in the code behind of the page, but of course in a real world app, some of this can be done through MVVM. In the constructor of the page we will be calling two methods, InitImages and LoadImages, the first one will define the images we are going to use and the second method will load them inside the StackPanel

private void InitImages()
{
_images.Add(new Image() { Source = new BitmapImage(new Uri(@"/Images/sink1.jpg", UriKind.Relative)), Width = 480 });
_images.Add(new Image() { Source = new BitmapImage(new Uri(@"/Images/sink2.jpg", UriKind.Relative)), Width = 480 });
_images.Add(new Image() { Source = new BitmapImage(new Uri(@"/Images/sink3.jpg", UriKind.Relative)), Width = 480 });
_images.Add(new Image() { Source = new BitmapImage(new Uri(@"/Images/sink4.jpg", UriKind.Relative)), Width = 480 });
_images.Add(new Image() { Source = new BitmapImage(new Uri(@"/Images/sink5.jpg", UriKind.Relative)), Width = 480 });
}
 
private void LoadImages()
{
_images.ForEach(item => this.ImageList.Children.Add(item));
}

What we want to do, is change the HorizontalOffset of the ScrollViewer to navigate through the carousel, but this can't be done directly from within a StoryBoard! This because the HorizontalOffset property is readonly and can only be set through use of the ScrollToHorizontalOffset method. So we need to implement a work around...

We can, however, tweak a property on the page from within a StoryBoard and the only thing we will be doing, is passing this through to the HorizontalOffset of the ScrollViewer. This property on the page will be a DependencyProperty.

private DependencyProperty _horizontalOffsetProperty = DependencyProperty.Register("HorizontalOffset", typeof(double), typeof(CarouselPoor), new PropertyMetadata(0.0, OnHorizontalOffsetChanged));
 
private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
CarouselPoor app = d as CarouselPoor;
app.OnHorizontalOffsetChanged(e);
}
 
private void OnHorizontalOffsetChanged(DependencyPropertyChangedEventArgs e)
{
this.ValidateNavigation();
this.ImageCarousel.ScrollToHorizontalOffset((double)e.NewValue);
}
 
public CarouselPoor()
{
InitializeComponent();
 
this.InitImages();
this.LoadImages();
this.ValidateNavigation();
 
_scrollAnimation = new DoubleAnimation()
{
EasingFunction = new SineEase(),
Duration = TimeSpan.FromSeconds(0.5)
};
 
Storyboard.SetTarget(_scrollAnimation, this);
Storyboard.SetTargetProperty(_scrollAnimation, new PropertyPath(_horizontalOffsetProperty));
 
_scrollViewerStoryboard = new Storyboard();
_scrollViewerStoryboard.Children.Add(_scrollAnimation);
}

In the code above we create an animation and manipulate the HorizontalOffset. When the animation occurs we pass the value through to our own method in which we set the HorizontalOffset of the ScrollViewer

Only thing left to do, is actually triggering this animation / storyboard when the user presses one of the navigation buttons. Do note we need to set the correct values for start and endpoints of the scroll animation to let it scroll in the right direction. We also change the value of the SelectedPivotIndex property on the indicator, so that the user sees what image in the list is currently active.

private void ButtonLeft_Click(object sender, RoutedEventArgs e)
{
var startPosition = this.ImageCarousel.HorizontalOffset;
if (startPosition > 0)
{
_scrollAnimation.From = startPosition;
_scrollAnimation.To = startPosition - 480;
--this.Indicator.SelectedPivotIndex;
_scrollViewerStoryboard.Begin();
}
}
 
private void ButtonRight_Click(object sender, RoutedEventArgs e)
{
var startPosition = this.ImageCarousel.HorizontalOffset;
_scrollAnimation.From = 0 + startPosition;
_scrollAnimation.To = 480 + startPosition;
++this.Indicator.SelectedPivotIndex;
_scrollViewerStoryboard.Begin();
}

With all this done correctly, you should have a carousel that shows a nice animation while the user goes through the images.

Video demo

The media player is loading...

Downloads

A complete working demo can be downloaded here: File:ImageCarousel.zip

Related topics

A carousel is just one way of efficiently displaying related text and images. The articles below outline some other alternatives.

This page was last modified on 10 December 2013, at 11:36.
259 page views in the last 30 days.

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×