Navigation for CoverFlow
Posted by: the telerik blogs,
on 07 Oct 2009 |
View original | Bookmarked: 0 time(s)
The Silverlight team decided to remove the ScrollBar control that used to be part of CoverFlow's control template. One of the reasons behind this decision is the easiness by which you can now, using Silverlight 3 element binding, create your own navigation. To learn more about all changes introduced by the beta version check my previous blog post here. This article explains in details how you can create your own navigation using a range control, e.g. one that inherits from the RangeBase class.
The first thing we need to do is to declare a CoverFlow control with some items in a straight-forward manner.
<StackPanel x:Name="LayoutRoot"> <telerikNav:RadCoverFlow x:Name="cover" Height="600" ItemHeight="200" ItemWidth="200"> <telerikNav:RadCoverFlowItem Background="White"/> <telerikNav:RadCoverFlowItem Background="Red"/> <telerikNav:RadCoverFlowItem Background="Green"/> <telerikNav:RadCoverFlowItem Background="Yellow"/> <telerikNav:RadCoverFlowItem Background="Blue"/> <telerikNav:RadCoverFlowItem Background="Pink"/> </telerikNav:RadCoverFlow> </StackPanel>
To make things simpler you can either implement your own range control or choose amongst ScrollBar, RadNumericUpdown or RadSlider. Using element binding you can easily associate the SelectedIndex of the CoverFlow with the value of your range control like this.
<telerik:RadSlider Value="{Binding SelectedIndex, ElementName=cover, Mode=TwoWay}"/>
Now if you change the value of the slider control, the binding will also change the SelectedIndex of the CoverFlow control declared above. However, you also need to constraint the range from the Minimum possible index to the Maximum one. You can safely set the Minimum value to zero, on the other hand the Maximum value needs some further consideration as your collections will vary in size. Therefore, you need a binding that will always check the size of the collection and constraint the range control to it. The easiest way to do this is to create another binding that binds to the count of the items of your collection, like:
<telerik:RadSlider Value="{Binding SelectedIndex, ElementName=cover, Mode=TwoWay}" Minimum="0" Maximum="{Binding Items.Count, ElementName=cover}"/>
However, note that the Count is not zero based like the index array. Hence, we will have an extra element available in our range. Unfortunately, there is no way you can tell the expression binding to evaluate an expression that binds the property to a less than a certain number, e.g. Items.Count -1. However, you can create a simple ValueConverter that can do the heavy lifting for you. Here is a simple int to int value converter that just sums the value and the converter parameter.
public class IntToIntValueConverter : IValueConverter { object IValueConverter.Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int val; int param; if ((int.TryParse(value.ToString(), out val) && (int.TryParse(parameter.ToString(), out param)))) { return val + param; } return value; } object IValueConverter.ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is int && parameter is int) { return (int)value + (int)parameter; } return DependencyProperty.UnsetValue; } }
You can easily declare the value converter class as a static resource part of the page and associate it with the Converter property of the Binding Expression. You also need to provide the converter parameter, in our case, -1. Your final version should look similar to:
<UserControl.Resources> <local:IntToIntValueConverter x:Key="IntToIntValueConverter"/> </UserControl.Resources> <StackPanel x:Name="LayoutRoot"> <telerikNav:RadCoverFlow x:Name="cover" Height="600" ItemHeight="200" ItemWidth="200"> <telerikNav:RadCoverFlowItem Background="White"/> <telerikNav:RadCoverFlowItem Background="Red"/> <telerikNav:RadCoverFlowItem Background="Green"/> <telerikNav:RadCoverFlowItem Background="Yellow"/> <telerikNav:RadCoverFlowItem Background="Blue"/> <telerikNav:RadCoverFlowItem Background="Pink"/> </telerikNav:RadCoverFlow> <telerik:RadSlider Value="{Binding SelectedIndex, ElementName=cover, Mode=TwoWay}" Minimum="0" Maximum="{Binding Items.Count, ElementName=cover, Converter={StaticResource IntToIntValueConverter}, ConverterParameter=-1}"/> </StackPanel>
Note that all properties used in this example are inherited from the RangeBase control, thus you can easily change the name of the control and set some control-specific properties to have navigation based on RadNumericUpDown or ScrollBar like this:
Orientation="Horizontal" Value="{Binding SelectedIndex, ElementName=cover, Mode=TwoWay}" Minimum="0" Maximum="{Binding Items.Count, ElementName=cover, Converter={StaticResource IntToIntValueConverter}, ConverterParameter=-1}"/>
Or
<telerik:RadNumericUpDown ShowTextBox="False" Value="{Binding SelectedIndex, ElementName=cover, Mode=TwoWay}" Minimum="0" Maximum="{Binding Items.Count, ElementName=cover, Converter={StaticResource IntToIntValueConverter}, ConverterParameter=-1}"/>
I hope this will alleviate some of the hassle caused by the lack of navigation in our new CoverFlow control. Stay tuned for all new things the Telerik team has prepared.