When moving through items in an ItemsControl
or ScrollViewer
, can I loop the contents so that the first item comes "after" the last item (as perceived by the user)?
I have a custom ScrollViewer
that will animate between selections, which currently contains an ItemControl
. The XAML for setting up my control is as follows:
<local:AnimatedScrollControl x:Name="myScroll" Grid.Column="1" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
<ItemsControl x:Name="myList"
ItemsSource="{Binding SlidesList}"
ItemTemplate="{StaticResource SlideTemplateOne}"
VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</local:AnimatedScrollControl>
Each item in the ItemControl
takes up the entire visible area for the control, so the user only sees one item at a time. The image below represents the control in action, with the red box indicating the viewport. A timer moves to the next item automatically.
The code to shift the slides (simplified for brevity) currently looks like this:
private void NextSlide()
{
_currentSlide++;
// get the current offset
double offset = (double)myScroll.GetValue(AnimatedScrollControl.SlideOffsetProperty);
// get the width of the current slide
FrameworkElement elementContainer = myList.ItemContainerGenerator.ContainerFromItem(CurrentSlide) as FrameworkElement;
// set the `to` value for a single slide shift
double to = offset + elementContainer.ActualWidth;
if (_currentSlide == _items.Count)
{
to = 0;
_currentSlide = 0;
}
DoubleAnimation animation = new DoubleAnimation();
animation.EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut };
animation.From = offset;
animation.To = to;
animation.Duration = TimeSpan.FromMilliseconds(300);
myScroll.BeginAnimation(AnimatedScrollControl.SlideOffsetProperty, animation);
}
When the last slide is reached and the viewport is updated to the first slide, it scans all the slides in reverse to reach the beginning. Like so: What I would like to do is make it appear as if the viewport scan directly from 'Slide 5' to 'Slide 1', such as:
Is there a way I can set up my ItemsControl
or ScrollViewer
, or adjust my Animation
in order to achieve this?
My solution came in the form of using an old LoopFrame
class, written by Dr WPF.
http://drwpf.com/blog/2009/08/05/itemscontrol-n-is-for-natural-user-interface/