/// <summary> /// Update all positions. Launch every animations on all items with a unique StoryBoard /// </summary> private void UpdatePosition() { storyboard = new Storyboard(); isUpdatingPosition = true; for (int i = 0; i < this.internalList.Count; i++) { // Do not animate all items var inf = this.SelectedIndex - (MaxVisibleItems * 2); var sup = this.SelectedIndex + (MaxVisibleItems * 2); if (i < inf || i > sup) continue; var item = internalList[i]; PlaneProjection planeProjection = item.Projection as PlaneProjection; if (planeProjection == null) continue; // Get target projection var props = GetProjection(i, 0d); // Zindex and Opacity var deltaFromSelectedIndex = Math.Abs(this.SelectedIndex - i); int zindex = (this.internalList.Count * 100) - deltaFromSelectedIndex; Canvas.SetZIndex(item, zindex); Double opacity = 1d - (Math.Abs((Double)(i - this.SelectedIndex) / (MaxVisibleItems + 1))); var newVisibility = deltaFromSelectedIndex > MaxVisibleItems ? Visibility.Collapsed : Visibility.Visible; // Item already present if (item.Visibility == newVisibility && item.Visibility == Visibility.Visible) { storyboard.AddAnimation(item, TransitionDuration, props.Item1, "(UIElement.Projection).(PlaneProjection.LocalOffsetX)", this.EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item2, "(UIElement.Projection).(PlaneProjection.GlobalOffsetY)", this.EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item3, "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)", this.EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item4, "(UIElement.Projection).(PlaneProjection.RotationY)", this.EasingFunction); storyboard.AddAnimation(item, TransitionDuration, opacity, "Opacity", this.EasingFunction); } else if (newVisibility == Visibility.Visible) { // This animation will occur in the ArrangeOverride() method item.Visibility = newVisibility; item.Opacity = 0d; } else if (newVisibility == Visibility.Collapsed) { storyboard.AddAnimation(item, TransitionDuration, 0d, "Opacity", this.EasingFunction); storyboard.Completed += (sender, o) => item.Visibility = Visibility.Collapsed; } } // When storyboard completed, Invalidate storyboard.Completed += (sender, o) => { this.isUpdatingPosition = false; this.InvalidateArrange(); }; storyboard.Begin(); }
/// <summary> /// Update all positions. Launch every animations on all items with a unique StoryBoard. /// </summary> private void UpdatePosition() { var storyboard = new Storyboard(); _isUpdatingPosition = true; for (var i = 0; i < _internalList.Count; i++) { // TODO optimize (x2 ?) // don't animate all items var inf = SelectedIndex - (MaxVisibleItems * 2); var sup = SelectedIndex + (MaxVisibleItems * 2); if (i < inf || i > sup) { continue; } var item = _internalList[i]; var planeProjection = item.Projection as PlaneProjection; if (planeProjection == null) { continue; } // get target projection var props = GetProjection(i, 0d); // Zindex and Opacity var deltaFromSelectedIndex = Math.Abs(SelectedIndex - i); var zindex = (_internalList.Count * 100) - deltaFromSelectedIndex; SetZIndex(item, zindex); var opacity = 1d - (Math.Abs((double)(i - SelectedIndex) / (MaxVisibleItems + 1))); var newVisibility = deltaFromSelectedIndex > MaxVisibleItems ? Visibility.Collapsed : Visibility.Visible; // item already present if (item.Visibility == newVisibility && item.Visibility == Visibility.Visible) { storyboard.AddAnimation(item, TransitionDuration, props.Item1, "(UIElement.Projection).(PlaneProjection.LocalOffsetX)", EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item2, "(UIElement.Projection).(PlaneProjection.GlobalOffsetY)", EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item3, "(UIElement.Projection).(PlaneProjection.GlobalOffsetZ)", EasingFunction); storyboard.AddAnimation(item, TransitionDuration, props.Item4, "(UIElement.Projection).(PlaneProjection.RotationY)", EasingFunction); storyboard.AddAnimation(item, TransitionDuration, opacity, "Opacity", EasingFunction); } else switch (newVisibility) { case Visibility.Visible: // this animation will occur in the ArrangeOverride() method item.Visibility = newVisibility; item.Opacity = 0d; break; case Visibility.Collapsed: storyboard.AddAnimation(item, TransitionDuration, 0d, "Opacity", EasingFunction); storyboard.Completed += (sender, o) => { item.Visibility = Visibility.Collapsed; }; break; } } // start storyboard // when storyboard completed, InvalidateArrange() storyboard.Completed += (sender, o) => { _isUpdatingPosition = false; InvalidateArrange(); }; storyboard.Begin(); }
/// <summary> /// Arrange all items /// </summary> protected override Size ArrangeOverride(Size finalSize) { if (isUpdatingPosition) return finalSize; Double centerLeft = 0; Double centerTop = 0; this.Clip = new RectangleGeometry { Rect = new Rect(0, 0, finalSize.Width, finalSize.Height) }; // Set Canvas.SetZIndex(rectangle, 1); // Storyboard for all Items to appear var localStoryboard = new Storyboard(); for (int i = 0; i < this.internalList.Count; i++) { UIElement container = internalList[i]; Size desiredSize = container.DesiredSize; if (double.IsNaN(desiredSize.Width) || double.IsNaN(desiredSize.Height)) continue; // get the good center and top position if (centerLeft == 0 && centerTop == 0 && desiredSize.Width > 0 && desiredSize.Height > 0) { desiredWidth = desiredSize.Width; desiredHeight = desiredSize.Height; centerLeft = (finalSize.Width / 2) - (desiredWidth / 2); centerTop = (finalSize.Height - desiredHeight) / 2; } // Get position from SelectedIndex var deltaFromSelectedIndex = Math.Abs(this.SelectedIndex - i); // Get rect position var rect = new Rect(centerLeft, centerTop, desiredWidth, desiredHeight); container.Arrange(rect); Canvas.SetLeft(container, centerLeft); Canvas.SetTop(container, centerTop); // Apply Transform PlaneProjection planeProjection = container.Projection as PlaneProjection; if (planeProjection == null) continue; // Get an initial projection (without move) var props = GetProjection(i, 0d); planeProjection.LocalOffsetX = props.Item1; planeProjection.GlobalOffsetY = props.Item2; planeProjection.GlobalOffsetZ = props.Item3; planeProjection.RotationY = props.Item4; // calculate zindex and opacity int zindex = (this.internalList.Count * 100) - deltaFromSelectedIndex; double opacity = 1d - (Math.Abs((Double)(i - this.SelectedIndex) / (MaxVisibleItems + 1))); container.Opacity = opacity; // Item appears if (container.Visibility == Visibility.Visible && container.Opacity == 0d) localStoryboard.AddAnimation(container, TransitionDuration, 0, opacity, "Opacity", this.EasingFunction); else container.Opacity = opacity; Canvas.SetZIndex(container, zindex); } rectangle.Fill = new SolidColorBrush(Colors.Black); rectangle.Opacity = 0.9; Canvas.SetLeft(rectangle, 0); Canvas.SetTop(rectangle, (this.ActualHeight / 2)); Canvas.SetZIndex(rectangle, 1); rectangle.Width = this.ActualWidth; rectangle.Height = this.ActualHeight; if (localStoryboard.Children.Count > 0) localStoryboard.Begin(); return finalSize; }
protected override Size ArrangeOverride(Size finalSize) { if (_isUpdatingPosition) { return finalSize; } var centerLeft = 0.0; var centerTop = 0.0; Clip = new RectangleGeometry { Rect = new Rect(0, 0, finalSize.Width, finalSize.Height) }; // storyboard for all items to appear var localStoryboard = new Storyboard(); for (var i = 0; i < _internalList.Count; i++) { var container = _internalList[i]; var desiredSize = container.DesiredSize; if (double.IsNaN(desiredSize.Width) || double.IsNaN(desiredSize.Height)) { continue; } // get the good center and top position if (centerLeft == 0 && centerTop == 0 && desiredSize.Width > 0 && desiredSize.Height > 0) { _desiredWidth = desiredSize.Width; _desiredHeight = desiredSize.Height; centerLeft = (finalSize.Width / 2) - (_desiredWidth / 2); centerTop = (finalSize.Height - _desiredHeight) / 2; } // get delta position from SelectedIndex var deltaFromSelectedIndex = Math.Abs(SelectedIndex - i); // get rect position var rect = new Rect(centerLeft, centerTop, _desiredWidth, _desiredHeight); container.Arrange(rect); SetLeft(container, centerLeft); SetTop(container, centerTop); // get an initial projection (without move) // apply transformation var planeProjection = container.Projection as PlaneProjection; if (planeProjection == null) continue; var props = GetProjection(i, 0d); planeProjection.LocalOffsetX = props.Item1; planeProjection.GlobalOffsetY = props.Item2; planeProjection.GlobalOffsetZ = props.Item3; planeProjection.RotationY = props.Item4; // calculate zindex and opacity var zindex = (_internalList.Count * 100) - deltaFromSelectedIndex; var opacity = 1d - (Math.Abs((double)(i - SelectedIndex) / (MaxVisibleItems + 1))); SetZIndex(container, zindex); container.Opacity = opacity; // item appearance if (container.Visibility == Visibility.Visible && container.Opacity == 0.0) { localStoryboard.AddAnimation(container, TransitionDuration, 0, opacity, "Opacity", EasingFunction); } else { container.Opacity = opacity; } } //rectangle.Fill = new SolidColorBrush(Colors.Black); //rectangle.Opacity = 0.9; //Canvas.SetLeft(rectangle, 0); //Canvas.SetTop(rectangle, (this.ActualHeight / 2)); //Canvas.SetZIndex(rectangle, 1); //rectangle.Width = this.ActualWidth; //rectangle.Height = this.ActualHeight; // start storyboard if (localStoryboard.Children.Count > 0) { localStoryboard.Begin(); } return finalSize; }