Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

WPF: Carousel Control

, , 18 Apr 2011
Highly customisable WPF Carousel control.
Carousel.zip
Carousel
Carousel
bin
Debug
Carousel.dll
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
Release
Carousel.csproj.user
Helpers
Images
next.png
previous.png
Lib
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
obj
x86
Debug
TempPE
Properties
Settings.settings
CarouselMVVM
bin
Debug
Carousel.dll
CarouselMVVM.exe
CarouselMVVM.vshost.exe
CarouselMVVM.vshost.exe.manifest
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
Release
CarouselMVVM.csproj.user
Commands
Lib
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
obj
x86
Debug
TempPE
Properties
Settings.settings
ViewModels
CarouselWPFTestApp
Application.ico
bin
Debug
Carousel.dll
CarouselWPFTestApp.exe
CarouselWPFTestApp.vshost.exe
CarouselWPFTestApp.vshost.exe.manifest
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
Release
CarouselWPFTestApp.csproj.user
Images
BlackArrowNext.png
BlackArrowPrevious.png
customize.png
female.png
male.png
option1.png
robot1.png
robot2.png
robot3.png
robot4.png
robot5.png
robot6.png
robot7.png
robot8.png
robot9.png
Lib
Expression.Samples.PathListBoxUtils.dll
Microsoft.Expression.Controls.dll
Microsoft.Expression.Drawing.dll
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll
Model
obj
Debug
Resources
TempPE
Properties
Resources
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.Windows.Media.Animation;
using Expression.Samples.PathListBoxUtils;
using System.Windows.Interactivity;

using Carousel.Helpers;
using System.ComponentModel;
using Microsoft.Expression.Controls;
using System.Windows.Automation.Peers;
using System.Windows.Automation.Provider;
using System.Diagnostics;


namespace Carousel
{
    public enum PathType { Ellipse, Wave, Diagonal, ZigZag, Custom };
    public enum ButtonPosition
    {
        TopLeft, TopCenter, TopRight, LeftCenter,
        RightCenter, BottomLeft, BottomCenter, BottomRight
    };


    /// <summary>
    /// The Carousel itself is based on PathListBox and PathListBoxUtils 
    /// using the codeplex available PathListBoxutils
    /// http://expressionblend.codeplex.com/wikipage?title=CarouselWPFTestAppUtils&referringTitle=Documentation
    /// 
    /// This article is also useful to see how the basic Carousel is made
    /// http://www.microsoft.com/design/toolbox/tutorials/CarouselWPFTestApp/carousel.aspx
    /// </summary>
    public partial class CarouselControl : UserControl
    {
        #region Data
        private List<PathListBoxItemTransformer> transformers = new List<PathListBoxItemTransformer>();
        private PathListBoxScrollBehavior pathListBoxScrollBehavior;
        #endregion

        #region Ctor
        public CarouselControl()
        {
            InitializeComponent();
            this.Loaded += CarouselControl_Loaded;
            pathListBox.SelectionChanged += PathListBox_SelectionChanged;
        }

        #endregion

        #region Private Methods

        private static bool IsValidNumberOfItemsOnPath(object value)
        {
            int v = (int)value;
            return (!v.Equals(int.MinValue) && !v.Equals(int.MaxValue));
        }


        private void SetButtonPosition(ButtonPosition buttonPosition)
        {
            switch (buttonPosition)
            {
                case ButtonPosition.TopLeft:
                    spButtons.VerticalAlignment = VerticalAlignment.Top;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Left;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;
                case ButtonPosition.TopCenter:
                    spButtons.VerticalAlignment = VerticalAlignment.Top;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Center;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;
                case ButtonPosition.TopRight:
                    spButtons.VerticalAlignment = VerticalAlignment.Top;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Right;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;
                case ButtonPosition.LeftCenter:
                    spButtons.VerticalAlignment = VerticalAlignment.Center;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Left;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Vertical;
                    break;
                case ButtonPosition.RightCenter:
                    spButtons.VerticalAlignment = VerticalAlignment.Center;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Right;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Vertical;
                    break;
                case ButtonPosition.BottomLeft:
                    spButtons.VerticalAlignment = VerticalAlignment.Bottom;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Left;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;
                case ButtonPosition.BottomCenter:
                    spButtons.VerticalAlignment = VerticalAlignment.Bottom;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Center;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;
                case ButtonPosition.BottomRight:
                    spButtons.VerticalAlignment = VerticalAlignment.Bottom;
                    spButtons.HorizontalAlignment = HorizontalAlignment.Right;
                    spButtons.Orientation = System.Windows.Controls.Orientation.Horizontal;
                    break;

            }
        }

        private void SetVisibilityForPath(PathType pathType)
        {
            foreach (UIElement uiElement in gridForKnownPaths.Children)
            {
                uiElement.Visibility = Visibility.Collapsed;
            }

            switch (pathType)
            {
                case PathType.Ellipse:
                    this.ellipsePath.Visibility = Visibility.Visible;
                    pathListBox.LayoutPaths[0].SourceElement = this.ellipsePath;
                    break;
                case PathType.Wave:
                    this.wavePath.Visibility = Visibility.Visible;
                    pathListBox.LayoutPaths[0].SourceElement = this.wavePath;
                    break;
                case PathType.Diagonal:
                    this.diagonalPath.Visibility = Visibility.Visible;
                    pathListBox.LayoutPaths[0].SourceElement = this.diagonalPath;
                    break;
                case PathType.ZigZag:
                    this.zigzagPath.Visibility = Visibility.Visible;
                    pathListBox.LayoutPaths[0].SourceElement = this.zigzagPath;
                    break;
                case PathType.Custom:
                    pathListBox.LayoutPaths[0].SourceElement = CustomPathElement;
                    break;

            }
        }

        private void CarouselControl_Loaded(object sender, RoutedEventArgs e)
        {
            BehaviorCollection behaviors = Interaction.GetBehaviors(pathListBox);
            pathListBoxScrollBehavior = (PathListBoxScrollBehavior)behaviors
                .Where(x => x.GetType() == typeof(PathListBoxScrollBehavior)).FirstOrDefault();
        }

        private void PathListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RaiseSelectionChangedEvent(e);
        }

        private void PathListBoxItemTransformer_Loaded(object sender, RoutedEventArgs e)
        {
            PathListBoxItemTransformer trans = sender as PathListBoxItemTransformer;
            trans.Ease = AnimationEaseIn;
            trans.OpacityRange = OpacityRange;
            trans.ScaleRange = ScaleRange;
            trans.AngleRange = AngleRange;
            transformers.Add(trans);

        }


        /// <summary>
        /// The pathListBox transitioning did not seem to work when I used an ICommand
        /// could be it was firing to often and causing some mischief to happen
        /// </summary>
        private void PreviousButton_Click(object sender, RoutedEventArgs e)
        {
            if (pathListBox.SelectedIndex > 0)
            {
                pathListBox.SelectedIndex = pathListBox.SelectedIndex - 1;
            }
            else
            {
                pathListBox.SelectedIndex = pathListBox.Items.Count - 1;
            }

            pathListBox.SelectedItem = pathListBox.Items[pathListBox.SelectedIndex];
        }

        /// <summary>
        /// The pathListBox transitioning did not seem to work when I used an ICommand
        /// could be it was firing to often and causing some mischief to happen
        /// </summary>
        private void NextButton_Click(object sender, RoutedEventArgs e)
        {
            if (pathListBox.SelectedIndex < pathListBox.Items.Count - 1)
            {
                pathListBox.SelectedIndex = pathListBox.SelectedIndex + 1;
            }
            else
            {
                pathListBox.SelectedIndex = 0;
            }
            pathListBox.SelectedItem = pathListBox.Items[pathListBox.SelectedIndex];
        }

        #endregion

        #region Events

        #region SelectionChanged

        /// <summary>
        /// SelectionChanged Routed Event, which is raised when
        /// the internal PathListBox.SelectionChanged event occurs
        /// </summary>
        public static readonly RoutedEvent SelectionChangedEvent =
            EventManager.RegisterRoutedEvent("SelectionChanged",
            RoutingStrategy.Bubble, typeof(SelectionChangedEventHandler),
            typeof(CarouselControl));


        public event SelectionChangedEventHandler SelectionChanged
        {
            add { AddHandler(SelectionChangedEvent, value); }
            remove { RemoveHandler(SelectionChangedEvent, value); }
        }

        private SelectionChangedEventArgs RaiseSelectionChangedEvent(SelectionChangedEventArgs arg)
        {
            arg.RoutedEvent = SelectionChangedEvent;
            RoutedEventHelper.RaiseEvent(this, arg);
            return arg;
        }

        #endregion

        #endregion

        #region DPs

        #region CustomPathElement

        /// <summary>
        /// The FrameworkElement to use as custom path for Carousel
        /// </summary>
        public static readonly DependencyProperty CustomPathElementProperty =
            DependencyProperty.Register("CustomPathElement", typeof(FrameworkElement), typeof(CarouselControl),
                new FrameworkPropertyMetadata((FrameworkElement)null,
                    new PropertyChangedCallback(OnCustomPathElementChanged)));

        public FrameworkElement CustomPathElement
        {
            get { return (FrameworkElement)GetValue(CustomPathElementProperty); }
            set { SetValue(CustomPathElementProperty, value); }
        }

        private static void OnCustomPathElementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnCustomPathElementChanged(e);
        }

        protected virtual void OnCustomPathElementChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
                SetVisibilityForPath(PathType.Custom);
        }

        #endregion

        #region NavigationButtonPosition

        /// <summary>
        /// The Navigation ButtonPosition to use for the Carousel
        /// </summary>
        public static readonly DependencyProperty NavigationButtonPositionProperty =
            DependencyProperty.Register("NavigationButtonPosition", typeof(ButtonPosition), typeof(CarouselControl),
                new FrameworkPropertyMetadata((ButtonPosition)ButtonPosition.BottomCenter,
                    new PropertyChangedCallback(OnNavigationButtonPositionChanged)));

        public ButtonPosition NavigationButtonPosition
        {
            get { return (ButtonPosition)GetValue(NavigationButtonPositionProperty); }
            set { SetValue(NavigationButtonPositionProperty, value); }
        }

        private static void OnNavigationButtonPositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnNavigationButtonPositionChanged(e);
        }

        protected virtual void OnNavigationButtonPositionChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
                SetButtonPosition((ButtonPosition)e.NewValue);
        }

        #endregion

        #region PreviousButtonStyle

        /// <summary>
        /// Can be used to specify a new Style for Previous button to use for the Carousel
        /// </summary>
        public static readonly DependencyProperty PreviousButtonStyleProperty =
            DependencyProperty.Register("PreviousButtonStyle", typeof(Style), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Style)null,
                    new PropertyChangedCallback(OnPreviousButtonStyleChanged)));

        public Style PreviousButtonStyle
        {
            get { return (Style)GetValue(PreviousButtonStyleProperty); }
            set { SetValue(PreviousButtonStyleProperty, value); }
        }

        private static void OnPreviousButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnPreviousButtonStyleChanged(e);
        }

        protected virtual void OnPreviousButtonStyleChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
                this.previousButton.Style = (Style)e.NewValue;
        }

        #endregion

        #region NextButtonStyle

        /// <summary>
        /// Can be used to specify a new Style for Next button to use for the Carousel
        /// </summary>
        public static readonly DependencyProperty NextButtonStyleProperty =
            DependencyProperty.Register("NextButtonStyle", typeof(Style), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Style)null,
                    new PropertyChangedCallback(OnNextButtonStyleChanged)));

        public Style NextButtonStyle
        {
            get { return (Style)GetValue(NextButtonStyleProperty); }
            set { SetValue(NextButtonStyleProperty, value); }
        }

        private static void OnNextButtonStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnNextButtonStyleChanged(e);
        }

        protected virtual void OnNextButtonStyleChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
                this.nextButton.Style = (Style)e.NewValue;
        }

        #endregion

        #region PathType

        /// <summary>
        /// PathType Dependency Property
        /// </summary>
        public static readonly DependencyProperty PathTypeProperty =
            DependencyProperty.Register("PathType", typeof(PathType), typeof(CarouselControl),
                new FrameworkPropertyMetadata((PathType)PathType.Custom,
                    new PropertyChangedCallback(OnPathTypeChanged)));

        public PathType PathType
        {
            get { return (PathType)GetValue(PathTypeProperty); }
            set { SetValue(PathTypeProperty, value); }
        }

        private static void OnPathTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnPathTypeChanged(e);
        }

        protected virtual void OnPathTypeChanged(DependencyPropertyChangedEventArgs e)
        {
            SetVisibilityForPath((PathType)e.NewValue);
        }

        #endregion

        #region AnimationEaseIn

        /// <summary>
        /// AnimationEaseIn Dependency Property
        /// </summary>
        public static readonly DependencyProperty AnimationEaseInProperty =
            DependencyProperty.Register("AnimationEaseIn", typeof(EasingFunctionBase), typeof(CarouselControl),
                new FrameworkPropertyMetadata((EasingFunctionBase)null,
                    new PropertyChangedCallback(OnAnimationEaseInChanged)));

        public EasingFunctionBase AnimationEaseIn
        {
            get { return (EasingFunctionBase)GetValue(AnimationEaseInProperty); }
            set { SetValue(AnimationEaseInProperty, value); }
        }

        private static void OnAnimationEaseInChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnAnimationEaseInChanged(e);
        }

        protected virtual void OnAnimationEaseInChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                foreach (PathListBoxItemTransformer pathListBoxItemTransformer in transformers)
                {
                    pathListBoxItemTransformer.Ease = (EasingFunctionBase)e.NewValue;
                }
            }
        }

        #endregion

        #region AnimationEaseOut

        /// <summary>
        /// AnimationEaseOut Dependency Property
        /// </summary>
        public static readonly DependencyProperty AnimationEaseOutProperty =
            DependencyProperty.Register("AnimationEaseOut", typeof(EasingFunctionBase), typeof(CarouselControl),
                new FrameworkPropertyMetadata((EasingFunctionBase)null,
                    new PropertyChangedCallback(OnAnimationEaseOutChanged)));

        public EasingFunctionBase AnimationEaseOut
        {
            get { return (EasingFunctionBase)GetValue(AnimationEaseOutProperty); }
            set { SetValue(AnimationEaseOutProperty, value); }
        }

        private static void OnAnimationEaseOutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnAnimationEaseOutChanged(e);
        }

        protected virtual void OnAnimationEaseOutChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                if (pathListBoxScrollBehavior != null)
                    pathListBoxScrollBehavior.Ease = (EasingFunctionBase)e.NewValue;
            }
        }

        #endregion

        #region OpacityRange

        /// <summary>
        /// OpacityRange to use for PathListBoxItemTransformer
        /// </summary>
        public static readonly DependencyProperty OpacityRangeProperty =
            DependencyProperty.Register("OpacityRange", typeof(Point), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Point)new Point(0.7,1.0),
                    new PropertyChangedCallback(OnOpacityRangeChanged)));

        public Point OpacityRange
        {
            get { return (Point)GetValue(OpacityRangeProperty); }
            set { SetValue(OpacityRangeProperty, value); }
        }

        /// <summary>
        /// Handles changes to the OpacityRange property.
        /// </summary>
        private static void OnOpacityRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnOpacityRangeChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the OpacityRange property.
        /// </summary>
        protected virtual void OnOpacityRangeChanged(DependencyPropertyChangedEventArgs e)
        {
            foreach (PathListBoxItemTransformer pathListBoxItemTransformer in transformers)
            {
                pathListBoxItemTransformer.OpacityRange = (Point)e.NewValue;
            }

        }

        #endregion

        #region ScaleRange

        /// <summary>
        /// ScaleRange to use for PathListBoxItemTransformer
        /// </summary>
        public static readonly DependencyProperty ScaleRangeProperty =
            DependencyProperty.Register("ScaleRange", typeof(Point), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Point)new Point(1.0,3.0),
                    new PropertyChangedCallback(OnScaleRangeChanged)));

        public Point ScaleRange
        {
            get { return (Point)GetValue(ScaleRangeProperty); }
            set { SetValue(ScaleRangeProperty, value); }
        }

        /// <summary>
        /// Handles changes to the ScaleRange property.
        /// </summary>
        private static void OnScaleRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnScaleRangeChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the ScaleRange property.
        /// </summary>
        protected virtual void OnScaleRangeChanged(DependencyPropertyChangedEventArgs e)
        {
            foreach (PathListBoxItemTransformer pathListBoxItemTransformer in transformers)
            {
                pathListBoxItemTransformer.ScaleRange = (Point)e.NewValue;
            }

        }

        #endregion

        #region AngleRange

        /// <summary>
        /// AngleRange to use for PathListBoxItemTransformer
        /// </summary>
        public static readonly DependencyProperty AngleRangeProperty =
            DependencyProperty.Register("AngleRange", typeof(Point), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Point)new Point(0.0,0.0),
                    new PropertyChangedCallback(OnAngleRangeChanged)));

        public Point AngleRange
        {
            get { return (Point)GetValue(AngleRangeProperty); }
            set { SetValue(AngleRangeProperty, value); }
        }

        /// <summary>
        /// Handles changes to the AngleRange property.
        /// </summary>
        private static void OnAngleRangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnAngleRangeChanged(e);
        }

        /// <summary>
        /// Provides derived classes an opportunity to handle changes to the AngleRange property.
        /// </summary>
        protected virtual void OnAngleRangeChanged(DependencyPropertyChangedEventArgs e)
        {
            foreach (PathListBoxItemTransformer pathListBoxItemTransformer in transformers)
            {
                pathListBoxItemTransformer.AngleRange = (Point)e.NewValue;
            }

        }

        #endregion

 
         //Path ListBox wrapped properties


        #region DataTemplateToUse
        /// <summary>
        /// The DataTemplate to use for the Carousel
        /// </summary>
        [Bindable(true)]
        public static readonly DependencyProperty DataTemplateToUseProperty =
            DependencyProperty.Register("DataTemplateToUse", typeof(DataTemplate), typeof(CarouselControl),
                new FrameworkPropertyMetadata((DataTemplate)null,
                    new PropertyChangedCallback(OnDataTemplateToUseChanged)));

        public DataTemplate DataTemplateToUse
        {
            get { return (DataTemplate)GetValue(DataTemplateToUseProperty); }
            set { SetValue(DataTemplateToUseProperty, value); }
        }

        private static void OnDataTemplateToUseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnDataTemplateToUseChanged(e);
        }

        protected virtual void OnDataTemplateToUseChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
                this.pathListBox.ItemTemplate = (DataTemplate)e.NewValue;
        }
        #endregion

        #region SelectedItem

        /// <summary>
        /// SelectedItem Dependency Property
        /// </summary>
        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(Object), typeof(CarouselControl),
                new FrameworkPropertyMetadata((Object)null,
                    new PropertyChangedCallback(OnSelectedItemChanged)));

        public Object SelectedItem
        {
            get { return (Object)pathListBox.GetValue(SelectedItemProperty); }
            set { pathListBox.SetValue(SelectedItemProperty, value); }
        }

        private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnSelectedItemChanged(e);
        }

        protected virtual void OnSelectedItemChanged(DependencyPropertyChangedEventArgs e)
        {
            object currentlySelected = pathListBox.SelectedItem;
            if (currentlySelected != e.NewValue)
            {
                pathListBox.SelectedItem = e.NewValue;
            }
        }



        #endregion

        #region ItemsSource

        /// <summary>
        /// The ItemsSource to use for the Carousel
        /// </summary>
        [Bindable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CarouselControl),
                new FrameworkPropertyMetadata((IEnumerable)null,
                    new PropertyChangedCallback(OnItemsSourceChanged)));

        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((CarouselControl)d).OnItemsSourceChanged(e);
        }

        protected virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            if (e.NewValue != null)
            {
                transformers.Clear();
                this.pathListBox.ItemsSource = (IEnumerable)e.NewValue;
            }
        }

        #endregion

        #region NumberOfItemsOnPath



        /// <summary>
        /// NumberOfItemsOnPath
        /// </summary>
        public static readonly DependencyProperty NumberOfItemsOnPathProperty = DependencyProperty.Register(
            "NumberOfItemsOnPath",
            typeof(int),
            typeof(CarouselControl),
            new FrameworkPropertyMetadata(
                7,
                FrameworkPropertyMetadataOptions.None,
                new PropertyChangedCallback(OnNumberOfItemsOnPathChanged),
                new CoerceValueCallback(CoerceNumberOfItemsOnPath)
            ),
            new ValidateValueCallback(IsValidNumberOfItemsOnPath)
        );

        //property accessors
        public int NumberOfItemsOnPath
        {
            get { return (int)GetValue(NumberOfItemsOnPathProperty); }
            set { SetValue(NumberOfItemsOnPathProperty, value); }
        }


        /// <summary>
        /// Coerce NumberOfItemsOnPath value if not within limits
        /// </summary>
        private static object CoerceNumberOfItemsOnPath(DependencyObject d, object value)
        {
            CarouselControl depObj = (CarouselControl)d;
            int current = (int)value;
            if (current < depObj.MinNumberOfItemsOnPath) current = depObj.MinNumberOfItemsOnPath;
            if (current > depObj.MaxNumberOfItemsOnPath) current = depObj.MaxNumberOfItemsOnPath;
            return current;
        }

        private static void OnNumberOfItemsOnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(MinNumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceMinNumberOfItemsOnPath")
            d.CoerceValue(MaxNumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceMaxNumberOfItemsOnPath")
            CarouselControl depObj = (CarouselControl)d;
            depObj.pathListBox.LayoutPaths[0].Capacity = (double)depObj.NumberOfItemsOnPath;


        }
        #endregion

        #region MinNumberOfItemsOnPath

        /// <summary>
        /// MinNumberOfItemsOnPath DP
        /// </summary>
        public static readonly DependencyProperty MinNumberOfItemsOnPathProperty = DependencyProperty.Register(
        "MinNumberOfItemsOnPath",
        typeof(int),
        typeof(CarouselControl),
        new FrameworkPropertyMetadata(
            3,
            FrameworkPropertyMetadataOptions.None,
            new PropertyChangedCallback(OnMinNumberOfItemsOnPathChanged),
            new CoerceValueCallback(CoerceMinNumberOfItemsOnPath)
        ),
        new ValidateValueCallback(IsValidNumberOfItemsOnPath));

        //property accessors
        public int MinNumberOfItemsOnPath
        {
            get { return (int)GetValue(MinNumberOfItemsOnPathProperty); }
            set { SetValue(MinNumberOfItemsOnPathProperty, value); }
        }

        /// <summary>
        /// Coerce MinNumberOfItemsOnPath value if not within limits
        /// </summary>
        private static void OnMinNumberOfItemsOnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(MaxNumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceMaxNumberOfItemsOnPath")
            d.CoerceValue(NumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceNumberOfItemsOnPath")
        }

        private static object CoerceMinNumberOfItemsOnPath(DependencyObject d, object value)
        {
            CarouselControl depObj = (CarouselControl)d;
            int min = (int)value;
            if (min > depObj.MaxNumberOfItemsOnPath) min = depObj.MaxNumberOfItemsOnPath;
            return min;
        }
        #endregion

        #region MaxNumberOfItemsOnPath

        /// <summary>
        /// MaxNumberOfItemsOnPath
        /// </summary>
        public static readonly DependencyProperty MaxNumberOfItemsOnPathProperty = DependencyProperty.Register(
            "MaxNumberOfItemsOnPath",
            typeof(int),
            typeof(CarouselControl),
            new FrameworkPropertyMetadata(
                10,
                FrameworkPropertyMetadataOptions.None,
                new PropertyChangedCallback(OnMaxNumberOfItemsOnPathChanged),
                new CoerceValueCallback(CoerceMaxNumberOfItemsOnPath)
            ),
            new ValidateValueCallback(IsValidNumberOfItemsOnPath)
        );

        //property accessors
        public int MaxNumberOfItemsOnPath
        {
            get { return (int)GetValue(MaxNumberOfItemsOnPathProperty); }
            set { SetValue(MaxNumberOfItemsOnPathProperty, value); }
        }

        /// <summary>
        /// Coerce MaxNumberOfItemsOnPath value if not within limits
        /// </summary>
        private static object CoerceMaxNumberOfItemsOnPath(DependencyObject d, object value)
        {
            CarouselControl depObj = (CarouselControl)d;
            int max = (int)value;
            if (max < depObj.MinNumberOfItemsOnPath) max = depObj.MinNumberOfItemsOnPath;
            return max;
        }

        private static void OnMaxNumberOfItemsOnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.CoerceValue(MinNumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceMinNumberOfItemsOnPath")
            d.CoerceValue(NumberOfItemsOnPathProperty);  //invokes the CoerceValueCallback delegate ("CoerceNumberOfItemsOnPath")
        }
        #endregion

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

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

About the Authors

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
 
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
 
Both of these at Sussex University UK.
 
Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Marcelo Ricardo de Oliveira
Software Developer
Brazil Brazil
Marcelo Ricardo de Oliveira is a senior software developer who lives with his lovely wife Luciana and his little buddy and stepson Kauê in Guarulhos, Brazil, is co-founder of the Brazilian TV Guide TV Map and currently works for ILang Educação.
 
He is often working with serious, enterprise projects, although in spare time he's trying to write fun Code Project articles involving WPF, Silverlight, XNA, HTML5 canvas, Windows Phone app development, game development and music.
 
Published Windows Phone apps:
 
 
Awards:
 
CodeProject MVP 2012
CodeProject MVP 2011
 
Best Web Dev article of March 2013
Best Web Dev article of August 2012
Best Web Dev article of May 2012
Best Mobile article of January 2012
Best Mobile article of December 2011
Best Mobile article of October 2011
Best Web Dev article of September 2011
Best Web Dev article of August 2011
HTML5 / CSS3 Competition - Second Prize
Best ASP.NET article of June 2011
Best ASP.NET article of May 2011
Best ASP.NET article of April 2011
Best C# article of November 2010
Best overall article of November 2010
Best C# article of October 2010
Best C# article of September 2010
Best overall article of September 2010
Best overall article of February 2010
Best C# article of November 2009

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 18 Apr 2011
Article Copyright 2011 by Sacha Barber, Marcelo Ricardo de Oliveira
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid