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

Channel9 3D Explorer with gestures (hybrid smart client)

, 10 Mar 2009
An article on viewing Channel9's RSS posts
using System;
using System.Collections.Generic;
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.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using _3DTools;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace _3DView
{
    /// <summary>
    /// Rotation direction
    /// </summary>
    public enum RotateDirection : int
    {
        /// <summary>
        /// None
        /// </summary>
        None = -1,
        /// <summary>
        /// Left direction
        /// </summary>
        Left = 0,
        /// <summary>
        /// Right direction
        /// </summary>
        Right = 1
    }

    /// <summary>
    /// Interaction logic for _3DViewControl.xaml
    /// </summary>
    [CLSCompliant(false)]
    public sealed partial class _3DViewControl : UserControl
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public _3DViewControl()
        {
            InitializeComponent();
            this.Children = new ObservableCollection<_3DViewElement>();
            //Init();
        }

        /// <summary>
        /// BackElement transf
        /// </summary>
        TransformGroup __BackElementRotation;

        /// <summary>
        /// Render transform for all content
        /// </summary>
        RotateTransform __ElementRotation;

        #region Proprietes
        /// <summary>
        /// Gets or sets the current item
        /// </summary>
        public int CurrentItem
        { get; set; }

        /// <summary>
        /// Gets or sets the current item offset on Z axis
        /// </summary>
        public double CurrentItemOffset { get; set; }

        /// <summary>
        /// Gets or sets the miliseconds in the animation duration
        /// </summary>
        public int Duration { get; set; }

        /// <summary>
        /// Gets a collection of child _3DViewElement objects.
        /// </summary>        
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ObservableCollection<_3DViewElement> Children { get; set; }

        /// <summary>
        /// Sets the Visibility of Flip button
        /// </summary>
        public bool ViewFlipButton
        {
            set
            {
                if (value == false)
                    this.FlipButton.Visibility = Visibility.Collapsed;
                else
                    this.FlipButton.Visibility = Visibility.Visible;
            }

            get
            {
                return this.FlipButton.Visibility == Visibility.Visible;
            }
        }

        /// <summary>
        /// flip button content
        /// </summary>
        public string FlipButtonContent
        {
            set
            {
                if (value == null)
                    return;

                this.FlipButton.Content = value;
            }
        }

        /// <summary>
        /// Gets or sets the Z coordonate of the camera position
        /// </summary>
        public double CameraZPosition
        {
            set
            {
                Point3D point = this.MyCamera.Position;

                this.MyCamera.Position = new Point3D(point.X, point.Y, value);
            }
            get
            {
                return this.MyCamera.Position.Z;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Removes the element located at an index
        /// </summary>
        /// <   </param>
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= this.MyInteractiveVisual3D.Children.Count)
                return;

            if (index > this.CurrentItem)
            {
                this.TranslateRightItems(RotateDirection.Left, index);
            }
            else
                if (index < CurrentItem)
                {
                    this.TranslateLeftItems(RotateDirection.Right, index + 1);
                    --this.CurrentItem;
                }
                else
                {
                    InteractiveVisual3D currentChild = this.MyInteractiveVisual3D.Children[index] as InteractiveVisual3D;
                    if (currentChild == null) return;

                    Transform3DGroup currentTransf = currentChild.Transform as Transform3DGroup;
                    TranslateTransform3D currentTranslate = (currentTransf.Children[0] as TranslateTransform3D);
                    RotateTransform3D currentRotation = (currentTransf.Children[1] as RotateTransform3D);

                    DoubleAnimation myCurrentTranslateXDoubleAnimation = null,
                                    myCurrentTranslateZDoubleAnimation = null,
                                    myCurrentRotateDoubleAnimation = null;

                    //check for left child
                    if (index - 1 >= 0 && this.MyInteractiveVisual3D.Children[index - 1] != null)
                    {
                        currentChild = this.MyInteractiveVisual3D.Children[index - 1] as InteractiveVisual3D;
                        if (currentChild == null) return;

                        currentTransf = currentChild.Transform as Transform3DGroup;
                        currentTranslate = (currentTransf.Children[0] as TranslateTransform3D);
                        currentRotation = (currentTransf.Children[1] as RotateTransform3D);

                        // Animate the rotation's angle.
                        currentRotation.CenterX = -1; currentRotation.CenterZ = 0;
                        myCurrentRotateDoubleAnimation = new DoubleAnimation();
                        myCurrentRotateDoubleAnimation.From = 45;
                        myCurrentRotateDoubleAnimation.To = 0;
                        myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 8));
                        myCurrentRotateDoubleAnimation.AutoReverse = false;
                        myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the rotation's angle property.
                        currentRotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                        // Animate the Translate's OffsetX.
                        myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                        myCurrentTranslateXDoubleAnimation.From = -1;
                        myCurrentTranslateXDoubleAnimation.To = 0;
                        myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                        myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                        myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the Translate's OffsetX property.
                        currentTranslate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                        // Animate the Translate's OffsetZ.
                        myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                        myCurrentTranslateZDoubleAnimation.From = 0;
                        myCurrentTranslateZDoubleAnimation.To = this.CurrentItemOffset;
                        myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                        myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                        myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the Translate's OffsetX property.
                        currentTranslate.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);

                        //translate all left items
                        this.TranslateLeftItems(RotateDirection.Right, index);

                        this.CurrentItem = index - 1;
                    }
                    else
                        if (index + 1 < this.MyInteractiveVisual3D.Children.Count && this.MyInteractiveVisual3D.Children[index + 1] != null)
                        {
                            currentChild = this.MyInteractiveVisual3D.Children[index + 1] as InteractiveVisual3D;
                            if (currentChild == null) return;

                            Transform3DGroup currentTransf1 = currentChild.Transform as Transform3DGroup;
                            TranslateTransform3D currentTranslate1 = (currentTransf1.Children[0] as TranslateTransform3D);
                            RotateTransform3D currentRotation1 = (currentTransf1.Children[1] as RotateTransform3D);

                            // Animate the rotation's angle.
                            currentRotation1.CenterX = 1; currentRotation1.CenterZ = 0;
                            myCurrentRotateDoubleAnimation = new DoubleAnimation();
                            myCurrentRotateDoubleAnimation.From = -45;
                            myCurrentRotateDoubleAnimation.To = 0;
                            myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                            myCurrentRotateDoubleAnimation.AutoReverse = false;
                            myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                            // Apply the animation to the rotation's angle property.
                            currentRotation1.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                            //currentTranslate = new TranslateTransform3D(-constVal, 0, this.CurrentItemOffset - constVal);
                            // Animate the Translate's OffsetX.
                            myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                            myCurrentTranslateXDoubleAnimation.From = 1;
                            myCurrentTranslateXDoubleAnimation.To = 0;
                            myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                            myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                            myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                            // Apply the animation to the Translate's OffsetX property.
                            currentTranslate1.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                            //Animate the Translate's OffsetZ.
                            myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                            myCurrentTranslateZDoubleAnimation.From = 0;
                            myCurrentTranslateZDoubleAnimation.To = this.CurrentItemOffset;
                            myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                            myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                            myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                            //Apply the animation to the Translate's OffsetX property.
                            currentTranslate1.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);

                            this.TranslateRightItems(RotateDirection.Left, index + 1);

                            this.CurrentItem = index + 1;
                        }
                }

            this.MyInteractiveVisual3D.Children.RemoveAt(index);
            this.Children.RemoveAt(index);
        }

        /// <summary>
        /// Adds a new child
        /// </summary>
        /// <param name="child">Child to add</param>
        public void AddNewChild(_3DView._3DViewElement child)
        {
            this.Children.Add(child);

            //the content element
            StackPanel panel = new StackPanel(); panel.RenderTransform = __ElementRotation;

            if (child.FrontElement != null)
            {
                //reflection
                Infragistics.ToyBox.Reflector r = new Infragistics.ToyBox.Reflector();
                r.ReflectionTarget = child.FrontElement;

                //add to content
                panel.Children.Add(child.FrontElement);
                panel.Children.Add(r);

            }

            if (child.BackElement != null)
            {
                //reflection
                Infragistics.ToyBox.Reflector r1 = new Infragistics.ToyBox.Reflector();
                r1.ReflectionTarget = child.BackElement;

                //add to content
                panel.Children.Add(child.BackElement); child.BackElement.Visibility = Visibility.Hidden;
                panel.Children.Add(r1); r1.Visibility = Visibility.Hidden;

                child.BackElement.RenderTransformOrigin = new Point(0.5, 0.5);
                r1.RenderTransformOrigin = new Point(0.5, 0.5);
                child.BackElement.RenderTransform = __BackElementRotation; r1.RenderTransform = __BackElementRotation;
            }            
            
            //add 2D content
            InteractiveVisual3D visualChild = new InteractiveVisual3D();
            visualChild.IsBackVisible = true;
            visualChild.Geometry = this.FindResource("ItemMesh") as MeshGeometry3D;
            visualChild.Visual = panel;

            Transform3DGroup transf = visualChild.Transform as Transform3DGroup;
            if (transf == null) transf = CreateTransform();

            RotateTransform3D rot = (transf.Children[1] as RotateTransform3D);
            TranslateTransform3D translate = (transf.Children[0] as TranslateTransform3D);

            transf.Children.Clear();

            if (this.Children.Count > 1)
            {
                translate.OffsetX = this.Children.Count - this.CurrentItem - 1;
                rot.CenterX = this.Children.Count - this.CurrentItem - 1;
                rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)-45);
            }
            else
            {
                translate.OffsetZ = this.CurrentItemOffset;
                rot.CenterX = 0;
                rot.CenterZ = this.CurrentItemOffset;
                rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, 0d);
            }
            transf.Children.Add(translate); transf.Children.Add(rot);
            visualChild.Transform = transf;

            this.MyInteractiveVisual3D.Children.Add(visualChild);
        }

        /// <summary>
        /// Adds a new child
        /// </summary>
        /// <param name="child">Child to add</param>
        void AddChild(_3DView._3DViewElement child)
        {
            //the content element
            StackPanel panel = new StackPanel();

            if (child.FrontElement != null)
            {
                //reflection
                Infragistics.ToyBox.Reflector r = new Infragistics.ToyBox.Reflector();
                r.ReflectionTarget = child.FrontElement;

                //add to content
                panel.Children.Add(child.FrontElement);
                panel.Children.Add(r);
            }

            if (child.BackElement != null)
            {
                //reflection
                Infragistics.ToyBox.Reflector r1 = new Infragistics.ToyBox.Reflector();
                r1.ReflectionTarget = child.BackElement;

                //add to content
                panel.Children.Add(child.BackElement); child.BackElement.Visibility = Visibility.Collapsed;
                panel.Children.Add(r1); r1.Visibility = Visibility.Collapsed;

                child.BackElement.RenderTransformOrigin = new Point(0.5, 0.5);
                r1.RenderTransformOrigin = new Point(0.5, 0.5);
                child.BackElement.RenderTransform = __BackElementRotation; r1.RenderTransform = __BackElementRotation;
            }
            //add 2D content
            InteractiveVisual3D visualChild = new InteractiveVisual3D();
            visualChild.IsBackVisible = true;
            visualChild.Geometry = this.FindResource("ItemMesh") as MeshGeometry3D;
            visualChild.Visual = panel;

            //add to list
            this.MyInteractiveVisual3D.Children.Add(visualChild);
        }

        /// <summary>
        /// Creates a new Transform3DGroup
        /// </summary>
        /// <returns></returns>
        static Transform3DGroup CreateTransform()
        {
            Transform3DGroup transf = new Transform3DGroup();

            transf.Children.Add(new TranslateTransform3D(0, 0, 0));
            transf.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0)));

            return transf;
        }

        /// <summary>
        /// Makes 3D View initializations
        /// </summary>
        public void Init()
        {
            __ElementRotation = new RotateTransform(-90);

            __BackElementRotation = new TransformGroup();
            __BackElementRotation.Children.Add(new ScaleTransform(-1, 1));

            if (this.CurrentItem == 0)
                this.CurrentItem = 0;

            if (this.CurrentItemOffset == 0)
                this.CurrentItemOffset = 1;

            if (this.Duration == 0)
                this.Duration = 800;


            this.SetChildTransform(RotateDirection.None);
        }

        /// <summary>
        /// Translates all left items to a direction
        /// </summary>
        /// <param name="direction">Direction to translate</param>
        /// <param name="toItem">From first item To item</param>
        void TranslateLeftItems(RotateDirection direction, int toItem)
        {
            for (int i = 0; i < ((direction == RotateDirection.Right) ? toItem - 1 : toItem); ++i)
            {
                InteractiveVisual3D child = this.MyInteractiveVisual3D.Children[i] as InteractiveVisual3D;
                if (child == null) return;

                Transform3DGroup transf = child.Transform as Transform3DGroup;
                TranslateTransform3D translate = (transf.Children[0] as TranslateTransform3D);
                RotateTransform3D rot = (transf.Children[1] as RotateTransform3D);
                DoubleAnimation myDoubleAnimation = null, myRotateDoubleAnimation = null;

                switch (direction)
                {
                    case RotateDirection.Right:
                        //Animate the translation's angle.
                        myDoubleAnimation = new DoubleAnimation();
                        myDoubleAnimation.From = translate.OffsetX;
                        myDoubleAnimation.To = translate.OffsetX + 1;
                        myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myDoubleAnimation.AutoReverse = false;
                        myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        //Apply the animation to the translation's angle property.
                        translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myDoubleAnimation);

                        // Animate the rotation's center.
                        myRotateDoubleAnimation = new DoubleAnimation();
                        myRotateDoubleAnimation.From = rot.CenterX;
                        myRotateDoubleAnimation.To = rot.CenterX + 1;
                        myRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myRotateDoubleAnimation.AutoReverse = false;
                        myRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the rotation's centerx property.
                        rot.BeginAnimation(RotateTransform3D.CenterXProperty, myRotateDoubleAnimation);
                        break;
                    case RotateDirection.Left:
                        //Animate the translation's angle.
                        myDoubleAnimation = new DoubleAnimation();
                        myDoubleAnimation.From = translate.OffsetX;
                        myDoubleAnimation.To = translate.OffsetX - 1;
                        myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myDoubleAnimation.AutoReverse = false;
                        myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the translation's angle property.
                        translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myDoubleAnimation);

                        // Animate the rotation's center.
                        myRotateDoubleAnimation = new DoubleAnimation();
                        myRotateDoubleAnimation.From = rot.CenterX;
                        myRotateDoubleAnimation.To = rot.CenterX - 1;
                        myRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myRotateDoubleAnimation.AutoReverse = false;
                        myRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the rotation's centerx property.
                        rot.BeginAnimation(RotateTransform3D.CenterXProperty, myRotateDoubleAnimation);
                        break;
                    default:
                        //do nothing
                        break;
                }
            }
        }

        /// <summary>
        /// Translates all right items from an item to a direction
        /// </summary>
        /// <param name="direction">Direction to translate</param>
        /// <param name="fromItem">From item to translate, to last item</param>
        void TranslateRightItems(RotateDirection direction, int fromItem)
        {
            for (int i = ((direction == RotateDirection.Right) ? fromItem + 2 : fromItem + 1); i < this.MyInteractiveVisual3D.Children.Count; ++i)
            {
                InteractiveVisual3D child = this.MyInteractiveVisual3D.Children[i] as InteractiveVisual3D;
                if (child == null) return;

                Transform3DGroup transf = child.Transform as Transform3DGroup;
                TranslateTransform3D translate = (transf.Children[0] as TranslateTransform3D);
                RotateTransform3D rot = (transf.Children[1] as RotateTransform3D);
                DoubleAnimation myDoubleAnimation = null, myRotateDoubleAnimation = null;

                switch (direction)
                {
                    case RotateDirection.Right:
                        // Animate the translation's offset.
                        myDoubleAnimation = new DoubleAnimation();
                        myDoubleAnimation.From = translate.OffsetX;
                        myDoubleAnimation.To = translate.OffsetX + 1;
                        myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myDoubleAnimation.AutoReverse = false;
                        myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the translation's offsetx property.
                        translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myDoubleAnimation);

                        // Animate the rotation's center.
                        myRotateDoubleAnimation = new DoubleAnimation();
                        myRotateDoubleAnimation.From = rot.CenterX;
                        myRotateDoubleAnimation.To = rot.CenterX + 1;
                        myRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myRotateDoubleAnimation.AutoReverse = false;
                        myRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the rotation's centerx property.
                        rot.BeginAnimation(RotateTransform3D.CenterXProperty, myRotateDoubleAnimation);
                        break;
                    case RotateDirection.Left:
                        // Animate the translation's offset.
                        myDoubleAnimation = new DoubleAnimation();
                        myDoubleAnimation.From = translate.OffsetX;
                        myDoubleAnimation.To = translate.OffsetX - 1;
                        myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myDoubleAnimation.AutoReverse = false;
                        myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                        // Apply the animation to the translation's angle property.
                        translate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myDoubleAnimation);

                        // Animate the rotation's center.
                        myRotateDoubleAnimation = new DoubleAnimation();
                        myRotateDoubleAnimation.From = rot.CenterX;
                        myRotateDoubleAnimation.To = rot.CenterX - 1;
                        myRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration));
                        myRotateDoubleAnimation.AutoReverse = false;
                        myRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                        // Apply the animation to the rotation's centerx property.
                        rot.BeginAnimation(RotateTransform3D.CenterXProperty, myRotateDoubleAnimation);
                        break;
                    default:
                        //do nothing
                        break;
                }
            }
        }

        /// <summary>
        /// Rotates the stack on a direction
        /// </summary>
        /// <param name="direction">Rotate direction</param>
        void RotateStack(RotateDirection direction)
        {
            //reset the current item transformations
            this.ResetCurrentItem(direction);

            #region translate the left items with one unit
            this.TranslateLeftItems(direction, this.CurrentItem);
            #endregion

            //bring to front next current item and put the last one in its place
            int index = this.CurrentItem;
            this.RotateItems(direction, ref index);
            this.CurrentItem = index;

            #region translate the right items with one unit
            this.TranslateRightItems(direction, this.CurrentItem);
            #endregion
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="direction"></param>
        /// <param name="index"></param>
        private void RotateItems(RotateDirection direction, ref int index)
        {
            InteractiveVisual3D currentChild = this.MyInteractiveVisual3D.Children[index] as InteractiveVisual3D;
            if (currentChild == null) return;

            Transform3DGroup currentTransf = currentChild.Transform as Transform3DGroup;
            TranslateTransform3D currentTranslate = (currentTransf.Children[0] as TranslateTransform3D);
            RotateTransform3D currentRotation = (currentTransf.Children[1] as RotateTransform3D);

            DoubleAnimation myCurrentTranslateXDoubleAnimation = null,
                            myCurrentTranslateZDoubleAnimation = null,
                            myCurrentRotateDoubleAnimation = null;

            switch (direction)
            {
                case RotateDirection.Right:
                    #region itemIndex

                    // Animate the rotation's angle.
                    currentRotation.CenterX = 1; currentRotation.CenterZ = 0;
                    myCurrentRotateDoubleAnimation = new DoubleAnimation();
                    myCurrentRotateDoubleAnimation.From = 0;
                    myCurrentRotateDoubleAnimation.To = -45;
                    myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentRotateDoubleAnimation.AutoReverse = false;
                    myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the rotation's angle property.
                    currentRotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                    // Animate the Translate's OffsetX.
                    myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateXDoubleAnimation.From = 0;
                    myCurrentTranslateXDoubleAnimation.To = 1;
                    myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                    // Animate the Translate's OffsetZ.
                    myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateZDoubleAnimation.From = this.CurrentItemOffset;
                    myCurrentTranslateZDoubleAnimation.To = 0;
                    myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);

                    #endregion
                    --index;
                    #region itemIndex - 1

                    currentChild = this.MyInteractiveVisual3D.Children[index] as InteractiveVisual3D;
                    if (currentChild == null) return;

                    currentTransf = currentChild.Transform as Transform3DGroup;
                    currentTranslate = (currentTransf.Children[0] as TranslateTransform3D);
                    currentRotation = (currentTransf.Children[1] as RotateTransform3D);

                    // Animate the rotation's angle.
                    currentRotation.CenterX = -1; currentRotation.CenterZ = 0;
                    myCurrentRotateDoubleAnimation = new DoubleAnimation();
                    myCurrentRotateDoubleAnimation.From = 45;
                    myCurrentRotateDoubleAnimation.To = 0;
                    myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentRotateDoubleAnimation.AutoReverse = false;
                    myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the rotation's angle property.
                    currentRotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                    // Animate the Translate's OffsetX.
                    myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateXDoubleAnimation.From = -1;
                    myCurrentTranslateXDoubleAnimation.To = 0;
                    myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                    // Animate the Translate's OffsetZ.
                    myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateZDoubleAnimation.From = 0;
                    myCurrentTranslateZDoubleAnimation.To = this.CurrentItemOffset;
                    myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);
                    #endregion
                    break;
                case RotateDirection.Left:
                    #region itemIndex

                    // Animate the rotation's angle.
                    currentRotation.CenterX = -1; currentRotation.CenterZ = 0;
                    myCurrentRotateDoubleAnimation = new DoubleAnimation();
                    myCurrentRotateDoubleAnimation.From = 0;
                    myCurrentRotateDoubleAnimation.To = 45;
                    myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentRotateDoubleAnimation.AutoReverse = false;
                    myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                    // Apply the animation to the rotation's angle property.
                    currentRotation.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                    //currentTranslate = new TranslateTransform3D(-constVal, 0, this.CurrentItemOffset - constVal);
                    // Animate the Translate's OffsetX.
                    myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateXDoubleAnimation.From = 0;
                    myCurrentTranslateXDoubleAnimation.To = -1;
                    myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                    //Animate the Translate's OffsetZ.
                    myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateZDoubleAnimation.From = this.CurrentItemOffset;
                    myCurrentTranslateZDoubleAnimation.To = 0;
                    myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    //Apply the animation to the Translate's OffsetX property.
                    currentTranslate.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);
                    #endregion
                    ++index;
                    #region itemIndex + 1

                    currentChild = this.MyInteractiveVisual3D.Children[index] as InteractiveVisual3D;
                    if (currentChild == null) return;

                    Transform3DGroup currentTransf1 = currentChild.Transform as Transform3DGroup;
                    TranslateTransform3D currentTranslate1 = (currentTransf1.Children[0] as TranslateTransform3D);
                    RotateTransform3D currentRotation1 = (currentTransf1.Children[1] as RotateTransform3D);

                    // Animate the rotation's angle.
                    currentRotation1.CenterX = 1; currentRotation1.CenterZ = 0;
                    myCurrentRotateDoubleAnimation = new DoubleAnimation();
                    myCurrentRotateDoubleAnimation.From = -45;
                    myCurrentRotateDoubleAnimation.To = 0;
                    myCurrentRotateDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentRotateDoubleAnimation.AutoReverse = false;
                    myCurrentRotateDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                    // Apply the animation to the rotation's angle property.
                    currentRotation1.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myCurrentRotateDoubleAnimation);

                    //currentTranslate = new TranslateTransform3D(-constVal, 0, this.CurrentItemOffset - constVal);
                    // Animate the Translate's OffsetX.
                    myCurrentTranslateXDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateXDoubleAnimation.From = 1;
                    myCurrentTranslateXDoubleAnimation.To = 0;
                    myCurrentTranslateXDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateXDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateXDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
                    // Apply the animation to the Translate's OffsetX property.
                    currentTranslate1.BeginAnimation(TranslateTransform3D.OffsetXProperty, myCurrentTranslateXDoubleAnimation);

                    //Animate the Translate's OffsetZ.
                    myCurrentTranslateZDoubleAnimation = new DoubleAnimation();
                    myCurrentTranslateZDoubleAnimation.From = 0;
                    myCurrentTranslateZDoubleAnimation.To = this.CurrentItemOffset;
                    myCurrentTranslateZDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(Duration / 2));
                    myCurrentTranslateZDoubleAnimation.AutoReverse = false;
                    myCurrentTranslateZDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);

                    //Apply the animation to the Translate's OffsetX property.
                    currentTranslate1.BeginAnimation(TranslateTransform3D.OffsetZProperty, myCurrentTranslateZDoubleAnimation);
                    #endregion
                    break;
                default:
                    //do nothing
                    break;
            }
        }

        /// <summary>
        /// Creates all children
        /// </summary>
        void CreateChildren()
        {
            for (int index = 0; index < this.Children.Count; ++index)
            {
                _3DViewElement child = this.Children[index];

                this.AddChild(child);
            }
        }

        /// <summary>
        /// Transforms all children in a direction
        /// </summary>
        /// <param name="direction">Rotate direction</param>
        void SetChildTransform(RotateDirection direction)
        {
            CreateChildren();

            this.ResetCurrentItem(direction);

            for (int i = 0; i < this.MyInteractiveVisual3D.Children.Count; ++i)
            {
                InteractiveVisual3D child = this.MyInteractiveVisual3D.Children[i] as InteractiveVisual3D;

                if (child == null) return;
                Transform3DGroup transf = child.Transform as Transform3DGroup;

                if (transf == null) transf = CreateTransform();

                FrameworkElement panel = child.Visual as FrameworkElement;
                panel.RenderTransform = __ElementRotation;

                int index = i;

                RotateTransform3D rot = (transf.Children[1] as RotateTransform3D);
                TranslateTransform3D translate = (transf.Children[0] as TranslateTransform3D);

                transf.Children.Clear();

                if (index == this.CurrentItem)
                {
                    translate.OffsetX = 0;
                    translate.OffsetZ = this.CurrentItemOffset;

                    rot.CenterZ = this.CurrentItemOffset;
                    rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)0);
                }
                else
                    if (index < this.CurrentItem)
                    {
                        if (direction == RotateDirection.None)
                        {
                            translate.OffsetX = index - this.CurrentItem;
                            rot.CenterX = index - this.CurrentItem;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)45);
                        }
                        else if (direction == RotateDirection.Left)
                        {
                            //we want to see a left item
                            translate.OffsetX++;
                            translate.OffsetZ = 0;
                            rot.CenterX = translate.OffsetX;
                            rot.CenterZ = 0;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)45);
                        }
                        else
                        {
                            //we want to see a right item
                            translate.OffsetX--;
                            translate.OffsetZ = 0;
                            rot.CenterX = translate.OffsetX;
                            rot.CenterZ = 0;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)45);
                        }
                    }
                    else
                    {
                        if (direction == RotateDirection.None)
                        {
                            translate.OffsetX = index - this.CurrentItem;
                            rot.CenterX = index - this.CurrentItem;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)-45);
                        }
                        else if (direction == RotateDirection.Left)
                        {
                            //we want to see a left item
                            translate.OffsetX++;
                            translate.OffsetZ = 0;
                            rot.CenterX = translate.OffsetX;
                            rot.CenterZ = 0;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)-45);
                        }
                        else
                        {
                            //we want to see a right item
                            translate.OffsetX--;
                            translate.OffsetZ = 0;
                            rot.CenterX = translate.OffsetX;
                            rot.CenterZ = 0;
                            rot.Rotation.SetValue(AxisAngleRotation3D.AngleProperty, (double)-45);
                        }
                    }

                transf.Children.Add(translate); transf.Children.Add(rot);
                child.Transform = transf;
            }
        }

        /// <summary>
        /// Resets the current item transform
        /// </summary>
        /// <param name="direction"></param>
        private void ResetCurrentItem(RotateDirection direction)
        {
            if (this.MyInteractiveVisual3D.Children.Count == 0) return;

            switch (direction)
            {
                case RotateDirection.Left:
                    //reset current item
                    InteractiveVisual3D child1 = this.MyInteractiveVisual3D.Children[this.CurrentItem] as InteractiveVisual3D;
                    if (child1 == null) return;
                    Transform3DGroup transf1 = child1.Transform as Transform3DGroup;
                    transf1.Children[0] = new TranslateTransform3D(0, 0, this.CurrentItemOffset);
                    transf1.Children[1] = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0d));
                    child1.Transform = transf1;

                    break;
                case RotateDirection.Right:
                    child1 = this.MyInteractiveVisual3D.Children[this.CurrentItem] as InteractiveVisual3D;
                    if (child1 == null) return;

                    transf1 = child1.Transform as Transform3DGroup;
                    transf1.Children[0] = new TranslateTransform3D(0, 0, this.CurrentItemOffset);
                    transf1.Children[1] = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 0d));
                    child1.Transform = transf1;
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Clears all children
        /// </summary>
        public void ClearChildren()
        {
            for (int i = this.Children.Count - 1; i >= 0; --i)
            {
                this.RemoveAt(i);
            }
        }

        /// <summary>
        /// Moves current item
        /// </summary>
        /// <param name="direction"></param>
        public void MoveItem(RotateDirection direction)
        {
            switch (direction)
            { 
                case RotateDirection.Left:
                    if (this.CurrentItem > 0)
                        this.RotateStack(RotateDirection.Right);
                    break;
                case RotateDirection.Right:
                    if (this.CurrentItem < this.MyInteractiveVisual3D.Children.Count - 1)
                        this.RotateStack(RotateDirection.Left);
                    break;

                default:
                    break;
            }
        }
        #endregion

        #region Event handlers

        /// <summary>
        /// Fires on Left rotation button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LeftButton_Click(object sender, RoutedEventArgs e)
        {
            this.MoveItem(RotateDirection.Left);
        }

        /// <summary>
        /// Fires on Right rotation button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RightButton_Click(object sender, RoutedEventArgs e)
        {
            this.MoveItem(RotateDirection.Right);
        }

        /// <summary>
        /// Flips current item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FlipButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.MyInteractiveVisual3D.Children.Count == 0) return;

            Transform3DGroup transf = this.MyInteractiveVisual3D.Children[this.CurrentItem].Transform as Transform3DGroup;

            RotateTransform3D rot = transf.Children[1] as RotateTransform3D;

            double angle = (double)rot.Rotation.GetValue(AxisAngleRotation3D.AngleProperty);

            rot = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), angle));
            rot.CenterX = 0;
            rot.CenterY = 0;
            rot.CenterZ = this.CurrentItemOffset;
            transf.Children[1] = rot;

            // Animate the rotation's angle.
            DoubleAnimation myDoubleAnimation = new DoubleAnimation();
            myDoubleAnimation.From = angle;
            myDoubleAnimation.To = 180 - Math.Abs(angle);
            myDoubleAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
            myDoubleAnimation.AutoReverse = false;
            myDoubleAnimation.RepeatBehavior = new RepeatBehavior(1d);
            // Apply the animation to the rotation's angle property.
            rot.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty, myDoubleAnimation);

            InteractiveVisual3D currentChild = this.MyInteractiveVisual3D.Children[this.CurrentItem] as InteractiveVisual3D;
            StackPanel content = currentChild.Visual as StackPanel;

            if (angle == 0)
            {
                if (content.Children.Count > 0)
                {
                    content.Children[0].Visibility = Visibility.Collapsed;
                    content.Children[1].Visibility = Visibility.Collapsed;
                }

                if (content.Children.Count > 2)
                {
                    content.Children[2].Visibility = Visibility.Visible;
                    content.Children[3].Visibility = Visibility.Visible;
                }
            }
            else
            {
                if (content.Children.Count > 2)
                {
                    content.Children[2].Visibility = Visibility.Collapsed;
                    content.Children[3].Visibility = Visibility.Collapsed;
                }

                if (content.Children.Count > 0)
                {
                    content.Children[0].Visibility = Visibility.Visible;
                    content.Children[1].Visibility = Visibility.Visible;
                }
            }
        }

        /// <summary>
        /// Previous position point
        /// </summary>
        Point __PreviousPosition;

        /// <summary>
        /// Overrides the OnMouseMove
        /// </summary>
        /// <param name="e">EventArgs</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
            {
                Point position = e.GetPosition(this);

                if (position == __PreviousPosition) return;

                if (position.Y < __PreviousPosition.Y - 50)
                {
                    this.CameraZPosition -= 0.1d;
                    __PreviousPosition = position;
                }

                if (position.Y > __PreviousPosition.Y + 50)
                {
                    this.CameraZPosition += 0.1d;
                    __PreviousPosition = position;
                }

                if (position.X > __PreviousPosition.X + 75)
                {
                    this.MoveItem(RotateDirection.Left);

                    __PreviousPosition = position;
                }

                if (position.X < __PreviousPosition.X - 75)
                {
                    this.MoveItem(RotateDirection.Right);

                    __PreviousPosition = position;
                }
            }
            else
                __PreviousPosition = e.GetPosition(this);
        }

        /// <summary>
        /// Overrides the OnMouseDown
        /// </summary>
        /// <param name="e">EventArgs</param>
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            base.OnMouseDown(e);

            __PreviousPosition = e.GetPosition(this);
        }

        /// <summary>
        /// Overrides the OnMouseUp
        /// </summary>
        /// <param name="e">EventArgs</param>
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            base.OnMouseUp(e);

            __PreviousPosition = e.GetPosition(this);
        }

        #endregion

        
    }

    /// <summary>
    /// Class for an element : front and back
    /// </summary>
    [CLSCompliant(false)]
    public sealed class _3DViewElement : FrameworkElement
    {
        /// <summary>
        /// Gets the front element
        /// </summary>
        public FrameworkElement FrontElement { get; set; }

        /// <summary>
        /// Gets the back element
        /// </summary>
        public FrameworkElement BackElement { get; set; }
    }
}

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 Microsoft Public License (Ms-PL)

Share

About the Author

Eusebiu Marcu
Software Developer (Senior)
Romania Romania
is a developer at IBM Romania.

| Advertise | Privacy | Mobile
Web01 | 2.8.140916.1 | Last Updated 10 Mar 2009
Article Copyright 2009 by Eusebiu Marcu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid