/// <summary>
        /// Handles the Arrange pass during Layout
        /// </summary>
        /// <param name="finalSize">Final Size of the control</param>
        /// <returns>Total size occupied by all the Children</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            if ((ItemsSource == null) || !ItemsSource.Any())
            {
                return(finalSize);
            }

            // Resize the rootContainer
            _rootContainer.Size = finalSize.ToVector2();

            var padding = Padding;

            var paddingSize = padding.CollapseThickness();
            var width       = finalSize.Width;
            var height      = finalSize.Height;

            _itemCount = ItemsSource.Count();

            _availableWidth  = (width - paddingSize.Width).Single();
            _availableHeight = (height - paddingSize.Height).Single();
            var gapCount              = _itemCount - 1;
            var totalGap              = (gapCount * ItemGap).Single();
            var availableNonGapWidth  = _availableWidth - totalGap;
            var availableNonGapHeight = _availableHeight;

            _itemWidth    = availableNonGapWidth / _itemCount;
            _itemHeight   = availableNonGapHeight;
            _bannerBounds = new Rect(padding.Left, padding.Top, _availableWidth, _availableHeight);

            // Update Visual sizes and surfaceImages
            var availableSize = new Vector2(_availableWidth, _availableHeight);

            _rootContainer.Size  = availableSize;
            _bgLayer.Size        = availableSize;
            _bgLayer.CenterPoint = new Vector3(_bgLayer.Size * 0.5f, 0);
            _topLayer.Size       = availableSize;

            // Check if any visual is currently selected. If yes then obtain its index.
            // The new visual at that index should be selected and added to the toplayer
            var selectedVisualIndex = -1;

            if (_selectedVisual != null)
            {
                foreach (var item in _fluidItems)
                {
                    selectedVisualIndex++;
                    if (ReferenceEquals(item.Key, _selectedVisual))
                    {
                        break;
                    }
                }
            }

            for (var index = 0; index < _surfaceImages.Count; index++)
            {
                // Get the surfaceImage
                var surfaceImage = _surfaceImages.ElementAt(index);

                // Get the visual corresponding to this surfaceImage
                var itemVisual = _surfaceVisuals[surfaceImage];

                if (itemVisual == null)
                {
                    continue;
                }

                itemVisual.Size        = availableSize;
                itemVisual.CenterPoint = new Vector3(itemVisual.Size * 0.5f, 0);
                var contentVisual = itemVisual.Children.ElementAt(0) as SpriteVisual;
                if (contentVisual == null)
                {
                    continue;
                }

                contentVisual.Size        = availableSize;
                contentVisual.CenterPoint = itemVisual.CenterPoint;
                (contentVisual.Brush as CompositionSurfaceBrush)?.UpdateSurfaceBrushOptions(Stretch, AlignX, AlignY);

                // Calculate the Inset Clip
                var left  = index * (_itemWidth + ItemGap.Single());
                var right = _availableWidth - (left + _itemWidth);
                itemVisual.Properties.InsertScalar("LeftInset", left);
                itemVisual.Properties.InsertScalar("RightInset", right);
                itemVisual.Clip = (index == selectedVisualIndex)
                    ? _compositor.CreateInsetClip(0, 0, 0, 0)
                    : _compositor.CreateInsetClip(left, 0, right, 0);

                // Center Point
                itemVisual.CenterPoint    = new Vector3(left + (_itemWidth / 2f), (float)padding.Top + (_itemHeight / 2f), 0);
                contentVisual.CenterPoint = itemVisual.CenterPoint;

                // Update Fluid Items
                _fluidItems[itemVisual] = new Rect(padding.Left + left, padding.Top, _itemWidth, _itemHeight);
            }

            // Update Animations' keyframes
            _expandRightInset.InsertKeyFrame(1f, _availableWidth - _itemWidth);
            _collapseInsetClip.InsertKeyFrame(1f, _availableWidth - _itemWidth);

            return(finalSize);
        }
        /// <summary>
        /// Creates the SurfaceImages based on the ItemsSource
        /// </summary>
        /// <returns>Task</returns>
        private async Task CreateSurfaceImagesAsync()
        {
            if (_surfaceImagesCreated)
            {
                return;
            }

            var padding = Padding;

            // Clear previous visuals
            _surfaceVisuals.Clear();
            _fluidItems.Clear();
            _bgLayer.Children.RemoveAll();
            _topLayer.Children.RemoveAll();
            _selectedVisual = null;
            // Dispose the surface images
            for (var i = 0; i < _surfaceImages.Count; i++)
            {
                var surfaceImage = _surfaceImages.ElementAt(i);
                surfaceImage.Dispose();
            }
            _surfaceImages.Clear();

            if ((ItemsSource == null) || !ItemsSource.Any())
            {
                return;
            }

            var options = ImageSurfaceOptions.Default;

            options.SurfaceBackgroundColor = Colors.Transparent;

            var availableSize = new Size(_availableWidth, _availableHeight);

            for (var i = 0; i < ItemsSource.Count(); i++)
            {
                // Create the surface image
                var surfaceImage = await _generator.CreateImageSurfaceAsync(ItemsSource.ElementAt(i), availableSize, options);

                _surfaceImages.Add(surfaceImage);

                // Add a visual for the background
                var containerVisual = _compositor.CreateSpriteVisual();
                containerVisual.Size   = availableSize.ToVector2();
                containerVisual.Brush  = _compositor.CreateColorBrush(ItemBackground);
                containerVisual.Offset = new Vector3((float)padding.Left, (float)padding.Top, 0);

                // Create the visual for the content
                var contentVisual = _compositor.CreateSpriteVisual();
                contentVisual.Size = availableSize.ToVector2();
                var surfaceBrush = _compositor.CreateSurfaceBrush(surfaceImage.Surface);
                surfaceBrush.UpdateSurfaceBrushOptions(Stretch, AlignX, AlignY);
                contentVisual.Brush = surfaceBrush;

                // Calculate the Inset Clip
                var left  = i * (_itemWidth + ItemGap.Single());
                var right = _availableWidth - (left + _itemWidth);
                containerVisual.Properties.InsertScalar("LeftInset", left);
                containerVisual.Properties.InsertScalar("RightInset", right);
                containerVisual.Clip = _compositor.CreateInsetClip(left, 0, right, 0);

                // Center Point
                containerVisual.CenterPoint        = new Vector3(left + (_itemWidth / 2f), (float)padding.Top + (_itemHeight / 2f), 0);
                contentVisual.CenterPoint          = containerVisual.CenterPoint;
                containerVisual.ImplicitAnimations = _implicitAnimationCollection;
                contentVisual.ImplicitAnimations   = _implicitAnimationCollection;

                // Set the container content
                containerVisual.Children.InsertAtTop(contentVisual);

                // Add to Background Layer
                _bgLayer.Children.InsertAtTop(containerVisual);

                // Add Visual to the fluid items
                _fluidItems[containerVisual]  = new Rect(padding.Left + left, padding.Top, _itemWidth, _itemHeight);
                _surfaceVisuals[surfaceImage] = containerVisual;
            }
        }
예제 #3
0
        /// <summary>
        /// Handles the Arrange pass during Layout
        /// </summary>
        /// <param name="finalSize">Final Size of the control</param>
        /// <returns>Total size occupied by all the Children</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            if ((ItemsSource == null) || (!ItemsSource.Any()))
            {
                return(finalSize);
            }

            var padding     = Padding;
            var paddingSize = padding.CollapseThickness();
            var width       = finalSize.Width;
            var height      = finalSize.Height;
            var itemCount   = ItemsSource.Count();

            _availableWidth  = (width - paddingSize.Width).Single();
            _availableHeight = (height - paddingSize.Height).Single();
            var gapCount              = itemCount - 1;
            var totalGap              = (gapCount * ItemGap).Single();
            var availableNonGapWidth  = _availableWidth - totalGap;
            var availableNonGapHeight = _availableHeight;

            _itemWidth    = availableNonGapWidth / itemCount;
            _itemHeight   = availableNonGapHeight;
            _bannerBounds = new Rect(padding.Left, padding.Top, _availableWidth, _availableHeight);

            // Check if any visual is currently selected. If yes then obtain its index.
            // The new visual at that index should be selected and added to the toplayer
            var selectedVisualIndex = -1;

            if (_selectedVisual != null)
            {
                foreach (var item in _fluidItems)
                {
                    selectedVisualIndex++;
                    if (ReferenceEquals(item.Key, _selectedVisual))
                    {
                        break;
                    }
                }
            }

            // Clear previous visuals
            _fluidItems.Clear();
            _rootContainer.Children.RemoveAll();
            _rootContainer.Size = finalSize.ToVector2();

            // Background Layer
            _bgLayer      = _compositor.CreateLayerVisual();
            _bgLayer.Size = _rootContainer.Size;
            _rootContainer.Children.InsertAtBottom(_bgLayer);
            _bgLayer.CenterPoint = new Vector3(_bgLayer.Size * 0.5f, 0);

            // Top Layer
            _topLayer      = _compositor.CreateLayerVisual();
            _topLayer.Size = _rootContainer.Size;
            _rootContainer.Children.InsertAtTop(_topLayer);

            // Create Visuals
            for (var i = 0; i < itemCount; i++)
            {
                // Add a visual for the background
                var bgVisual = _compositor.CreateSpriteVisual();
                bgVisual.Size  = new Vector2(_availableWidth, _availableHeight);
                bgVisual.Brush = _compositor.CreateColorBrush(ItemBackground);

                // Create the visual for the content
                var contentVisual = _compositor.CreateSpriteVisual();
                contentVisual.Offset = Vector3.Zero;
                contentVisual.Size   = new Vector2(_availableWidth, _availableHeight);

                // Load image from the Uri
                contentVisual.Brush = _compositor.CreateSurfaceBrush(_images.ElementAt(i).Surface);

                // Create the container for the content
                var container = _compositor.CreateContainerVisual();
                container.Offset = new Vector3((float)padding.Left, (float)padding.Top, 0);
                container.Size   = new Vector2(_availableWidth, _availableHeight);

                // Calculate the Inset Clip
                var left  = i * (_itemWidth + ItemGap.Single());
                var right = _availableWidth - (left + _itemWidth);
                container.Properties.InsertScalar("LeftInset", left);
                container.Properties.InsertScalar("RightInset", right);
                // If the current value of 'i' same as the index of the previously selected visual
                // then the InsetClip value should be appropriately set
                container.Clip = (i == selectedVisualIndex) ?
                                 _compositor.CreateInsetClip(0, 0, 0, 0) : _compositor.CreateInsetClip(left, 0, right, 0);

                // Center Point
                container.CenterPoint            = new Vector3(left + (_itemWidth / 2f), (float)padding.Top + (_itemHeight / 2f), 0);
                contentVisual.CenterPoint        = container.CenterPoint;
                container.ImplicitAnimations     = _implicitAnimationCollection;
                contentVisual.ImplicitAnimations = _implicitAnimationCollection;

                // Set the container content
                container.Children.InsertAtTop(contentVisual);
                container.Children.InsertAtBottom(bgVisual);

                // Is the current value of 'i' same as the index of the previously selected visual
                if (i == selectedVisualIndex)
                {
                    // Add to the Top Layer
                    _topLayer.Children.InsertAtTop(container);
                    _selectedVisual = container;
                }
                else
                {
                    // Add to Background Layer
                    _bgLayer.Children.InsertAtTop(container);
                }

                // Add Visual to the fluid items
                _fluidItems[container] = new Rect(padding.Left + left, padding.Top, _itemWidth, _itemHeight);
            }

            // If there was a previously selected visual then Scale back
            // and fade the other visuals in the banner
            if (selectedVisualIndex > -1)
            {
                //
                foreach (var child in _bgLayer.Children)
                {
                    child.Scale   = new Vector3(ScaleDownFactor, ScaleDownFactor, 1);
                    child.Opacity = TargetOpacity;
                }
            }

            // Update Animations' keyframes
            _expandRightInset.InsertKeyFrame(1f, _availableWidth - _itemWidth);
            _collapseInsetClip.InsertKeyFrame(1f, _availableWidth - _itemWidth);

            // Add the rootContainer to the visual tree
            ElementCompositionPreview.SetElementChildVisual(this, _rootContainer);

            return(base.ArrangeOverride(finalSize));
        }