// Token: 0x06005A25 RID: 23077 RVA: 0x0018D700 File Offset: 0x0018B900
        private static void VirtualizationPropertyChangePropagationRecursive(DependencyObject parent, Panel itemsHost)
        {
            UIElementCollection internalChildren = itemsHost.InternalChildren;
            int count = internalChildren.Count;

            for (int i = 0; i < count; i++)
            {
                IHierarchicalVirtualizationAndScrollInfo hierarchicalVirtualizationAndScrollInfo = internalChildren[i] as IHierarchicalVirtualizationAndScrollInfo;
                if (hierarchicalVirtualizationAndScrollInfo != null)
                {
                    TreeViewItem.IsVirtualizingPropagationHelper(parent, (DependencyObject)hierarchicalVirtualizationAndScrollInfo);
                    Panel itemsHost2 = hierarchicalVirtualizationAndScrollInfo.ItemsHost;
                    if (itemsHost2 != null)
                    {
                        VirtualizingPanel.VirtualizationPropertyChangePropagationRecursive((DependencyObject)hierarchicalVirtualizationAndScrollInfo, itemsHost2);
                    }
                }
            }
        }
Example #2
0
        private static void VirtualizationPropertyChangePropagationRecursive(DependencyObject parent, Panel itemsHost)
        {
            UIElementCollection children = itemsHost.InternalChildren;
            int childrenCount            = children.Count;

            for (int i = 0; i < childrenCount; i++)
            {
                IHierarchicalVirtualizationAndScrollInfo virtualizingChild = children[i] as IHierarchicalVirtualizationAndScrollInfo;
                if (virtualizingChild != null)
                {
                    TreeViewItem.IsVirtualizingPropagationHelper(parent, (DependencyObject)virtualizingChild);

                    Panel childItemsHost = virtualizingChild.ItemsHost;
                    if (childItemsHost != null)
                    {
                        VirtualizationPropertyChangePropagationRecursive((DependencyObject)virtualizingChild, childItemsHost);
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// Called when a new viewport is set on the child and it is about to be measured.
        /// Invalidates Measure on all elements between child.ItemsHost and this panel.
        /// </summary>
        private void InvalidateMeasureOnItemsHost(IHierarchicalVirtualizationAndScrollInfo virtualizingChild)
        {
            Debug.Assert(virtualizingChild != null, "This method should only be invoked for a virtualizing child");

            Panel childItemsHost = virtualizingChild.ItemsHost;
            if (childItemsHost != null)
            {
                Helper.InvalidateMeasureOnPath(childItemsHost, this, true /*duringMeasure*/);

                if (!(childItemsHost is VirtualizingStackPanel))
                {
                    //
                    // For non-VSPs recurse a level deeper
                    //
                    IList children =  childItemsHost.InternalChildren;
                    for (int i=0; i<children.Count; i++)
                    {
                        IHierarchicalVirtualizationAndScrollInfo virtualizingGrandChild = children[i] as IHierarchicalVirtualizationAndScrollInfo;
                        if (virtualizingGrandChild != null)
                        {
                            InvalidateMeasureOnItemsHost(virtualizingGrandChild);
                        }
                    }
                }
            }
        }
Example #4
0
        /// <summary>
        /// Called when to set a new viewport on the child when it is about to be measured.
        /// </summary>
        private void SetViewportForChild(
            bool isHorizontal,
            IContainItemStorage itemStorageProvider,
            bool areContainersUniformlySized,
            double uniformOrAverageContainerSize,
            bool mustDisableVirtualization,
            UIElement child,
            IHierarchicalVirtualizationAndScrollInfo virtualizingChild,
            object item,
            bool isBeforeFirstItem,
            bool isAfterFirstItem,
            double firstItemInViewportOffset,
            Rect parentViewport,
            VirtualizationCacheLength parentCacheSize,
            VirtualizationCacheLengthUnit parentCacheUnit,
            Size stackPixelSize,
            Size stackPixelSizeInViewport,
            Size stackPixelSizeInCacheBeforeViewport,
            Size stackPixelSizeInCacheAfterViewport,
            Size stackLogicalSize,
            Size stackLogicalSizeInViewport,
            Size stackLogicalSizeInCacheBeforeViewport,
            Size stackLogicalSizeInCacheAfterViewport,
            out Rect childViewport,
            ref VirtualizationCacheLength childCacheSize,
            ref VirtualizationCacheLengthUnit childCacheUnit)
        {
            childViewport = parentViewport;

            //
            // Adjust viewport offset for the child by deducting
            // the dimensions of the previous siblings.
            //
            if (isHorizontal)
            {
                if (isBeforeFirstItem)
                {
                    Size containerSize;
                    GetContainerSizeForItem(itemStorageProvider, item, isHorizontal, areContainersUniformlySized, uniformOrAverageContainerSize, out containerSize);
                    childViewport.X = (IsPixelBased ? stackPixelSizeInCacheBeforeViewport.Width : stackLogicalSizeInCacheBeforeViewport.Width) + containerSize.Width;
                    childViewport.Width = 0.0;
                }
                else if (isAfterFirstItem)
                {
                    childViewport.X = Math.Min(childViewport.X, 0) -
                                      (IsPixelBased ? stackPixelSizeInViewport.Width + stackPixelSizeInCacheAfterViewport.Width :
                                                       stackLogicalSizeInViewport.Width + stackLogicalSizeInCacheAfterViewport.Width);

                    childViewport.Width = Math.Max(childViewport.Width - stackPixelSizeInViewport.Width, 0.0);
                }
                else
                {
                    childViewport.X -= firstItemInViewportOffset;
                    childViewport.Width = Math.Max(childViewport.Width - stackPixelSizeInViewport.Width, 0.0);
                }

                if (parentCacheUnit == VirtualizationCacheLengthUnit.Item)
                {
                    childCacheSize = new VirtualizationCacheLength(
                        isAfterFirstItem || DoubleUtil.LessThanOrClose(childViewport.X, 0.0) ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheBeforeViewport - stackLogicalSizeInCacheBeforeViewport.Width, 0.0),
                        isBeforeFirstItem ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheAfterViewport - stackLogicalSizeInCacheAfterViewport.Width, 0.0));
                    childCacheUnit = VirtualizationCacheLengthUnit.Item;
                }
                else if (parentCacheUnit == VirtualizationCacheLengthUnit.Pixel)
                {
                    childCacheSize = new VirtualizationCacheLength(
                        isAfterFirstItem || DoubleUtil.LessThanOrClose(childViewport.X, 0.0) ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheBeforeViewport - stackPixelSizeInCacheBeforeViewport.Width, 0.0),
                        isBeforeFirstItem ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheAfterViewport - stackPixelSizeInCacheAfterViewport.Width, 0.0));
                    childCacheUnit = VirtualizationCacheLengthUnit.Pixel;
                }
            }
            else
            {
                if (isBeforeFirstItem)
                {
                    Size containerSize;
                    GetContainerSizeForItem(itemStorageProvider, item, isHorizontal, areContainersUniformlySized, uniformOrAverageContainerSize, out containerSize);
                    childViewport.Y = (IsPixelBased ? stackPixelSizeInCacheBeforeViewport.Height : stackLogicalSizeInCacheBeforeViewport.Height) + containerSize.Height;
                    childViewport.Height = 0.0;
                }
                else if (isAfterFirstItem)
                {
                    childViewport.Y = Math.Min(childViewport.Y, 0) -
                                      (IsPixelBased ? stackPixelSizeInViewport.Height + stackPixelSizeInCacheAfterViewport.Height :
                                                       stackLogicalSizeInViewport.Height + stackLogicalSizeInCacheAfterViewport.Height);

                    childViewport.Height = Math.Max(childViewport.Height - stackPixelSizeInViewport.Height, 0.0);
                }
                else
                {
                    childViewport.Y -= firstItemInViewportOffset;
                    childViewport.Height = Math.Max(childViewport.Height - stackPixelSizeInViewport.Height, 0.0);
                }

                if (parentCacheUnit == VirtualizationCacheLengthUnit.Item)
                {
                    childCacheSize = new VirtualizationCacheLength(
                        isAfterFirstItem || DoubleUtil.LessThanOrClose(childViewport.Y, 0.0) ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheBeforeViewport - stackLogicalSizeInCacheBeforeViewport.Height, 0.0),
                        isBeforeFirstItem ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheAfterViewport - stackLogicalSizeInCacheAfterViewport.Height, 0.0));
                    childCacheUnit = VirtualizationCacheLengthUnit.Item;
                }
                else if (parentCacheUnit == VirtualizationCacheLengthUnit.Pixel)
                {
                    childCacheSize = new VirtualizationCacheLength(
                        isAfterFirstItem || DoubleUtil.LessThanOrClose(childViewport.Y, 0.0) ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheBeforeViewport - stackPixelSizeInCacheBeforeViewport.Height, 0.0),
                        isBeforeFirstItem ?
                            0.0 :
                            Math.Max(parentCacheSize.CacheAfterViewport - stackPixelSizeInCacheAfterViewport.Height, 0.0));
                    childCacheUnit = VirtualizationCacheLengthUnit.Pixel;
                }
            }

            if (virtualizingChild != null)
            {
                virtualizingChild.Constraints = new HierarchicalVirtualizationConstraints(
                    childCacheSize,
                    childCacheUnit,
                    childViewport);
                virtualizingChild.InBackgroundLayout = MeasureCaches;
                virtualizingChild.MustDisableVirtualization = mustDisableVirtualization;
            }

            if (child is IHierarchicalVirtualizationAndScrollInfo)
            {
                //
                // Ensure that measure is invalid through the items panel
                // of the child, so it can react to the new viewport.
                //
                InvalidateMeasureOnItemsHost((IHierarchicalVirtualizationAndScrollInfo)child);
            }
        }
Example #5
0
        /// <summary>
        /// Adjusts viewport to accomodate the either the Header or ItemsPanel.
        /// </summary>
        private void AdjustNonScrollingViewport(
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            ref Rect viewport,
            ref VirtualizationCacheLength cacheLength,
            ref VirtualizationCacheLengthUnit cacheUnit,
            bool forHeader)
        {
            Debug.Assert(virtualizationInfoProvider != null, "This method should only be invoked for a virtualizing owner");
            Debug.Assert(cacheUnit != VirtualizationCacheLengthUnit.Page, "Page after cache size is not expected here.");

            Rect parentViewport = viewport;
            double sizeAfterStartViewportEdge = 0;
            double sizeBeforeStartViewportEdge = 0;
            double sizeAfterEndViewportEdge = 0;
            double sizeBeforeEndViewportEdge = 0;
            double cacheBeforeSize = cacheLength.CacheBeforeViewport;
            double cacheAfterSize = cacheLength.CacheAfterViewport;

            HierarchicalVirtualizationHeaderDesiredSizes headerDesiredSizes = virtualizationInfoProvider.HeaderDesiredSizes;
            HierarchicalVirtualizationItemDesiredSizes itemDesiredSizes = virtualizationInfoProvider.ItemDesiredSizes;

            Size pixelSize = forHeader ? headerDesiredSizes.PixelSize : itemDesiredSizes.PixelSize;
            Size logicalSize = forHeader ? headerDesiredSizes.LogicalSize : itemDesiredSizes.LogicalSize;

            RelativeHeaderPosition headerPosition = RelativeHeaderPosition.Top; // virtualizationInfoProvider.RelativeHeaderPosition;

            if ((forHeader && headerPosition == RelativeHeaderPosition.Left) ||
                (!forHeader && headerPosition == RelativeHeaderPosition.Right))
            {
                //
                // Adjust the offset
                //

                viewport.X -= IsPixelBased ? pixelSize.Width : logicalSize.Width;

                if (DoubleUtil.GreaterThan(parentViewport.X, 0))
                {
                    //
                    // Viewport is after the start of this panel
                    //

                    if (IsPixelBased && DoubleUtil.GreaterThan(pixelSize.Width, parentViewport.X))
                    {
                        //
                        // Header straddles the start edge of the viewport
                        //

                        sizeAfterStartViewportEdge = pixelSize.Width - parentViewport.X;
                        sizeBeforeStartViewportEdge = pixelSize.Width - sizeAfterStartViewportEdge;

                        viewport.Width = Math.Max(viewport.Width - sizeAfterStartViewportEdge, 0);

                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheBeforeSize = Math.Max(cacheBeforeSize - sizeBeforeStartViewportEdge, 0);
                        }
                        else
                        {
                            cacheBeforeSize = Math.Max(cacheBeforeSize - Math.Floor(logicalSize.Width * sizeBeforeStartViewportEdge / pixelSize.Width), 0);
                        }
                    }
                    else
                    {
                        //
                        // Header is completely before the start edge of the viewport. We do not need to
                        // adjust the cacheBefore size in this case because the cacheBefore is populated
                        // bottom up and we cant really be certain that the header will infact lie within the
                        // cacheBefore region.
                        //
                    }
                }
                else
                {
                    //
                    // Viewport is at or before this panel
                    //

                    if (DoubleUtil.GreaterThan(parentViewport.Width, 0))
                    {
                        if (DoubleUtil.GreaterThanOrClose(parentViewport.Width, pixelSize.Width))
                        {
                            //
                            // Header is completely within the viewport
                            //

                            viewport.Width = Math.Max(0, parentViewport.Width - pixelSize.Width);
                        }
                        else
                        {
                            //
                            // Header straddles the end edge of the viewport
                            //

                            sizeBeforeEndViewportEdge = parentViewport.Width;
                            sizeAfterEndViewportEdge = pixelSize.Width - sizeBeforeEndViewportEdge;

                            viewport.Width = 0;

                            if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                            {
                                cacheAfterSize = Math.Max(cacheAfterSize - sizeAfterEndViewportEdge, 0);
                            }
                            else
                            {
                                cacheAfterSize = Math.Max(cacheAfterSize - Math.Floor(logicalSize.Width * sizeAfterEndViewportEdge / pixelSize.Width), 0);
                            }
                        }
                    }
                    else
                    {
                        //
                        // Header is completely after the end edge of the viewport
                        //

                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheAfterSize = Math.Max(cacheAfterSize - pixelSize.Width, 0);
                        }
                        else
                        {
                            cacheAfterSize = Math.Max(cacheAfterSize - logicalSize.Width, 0);
                        }
                    }
                }
            }
            else if ((forHeader && headerPosition == RelativeHeaderPosition.Top) ||
                    (!forHeader && headerPosition == RelativeHeaderPosition.Bottom))
            {
                //
                // Adjust the offset
                //

                viewport.Y -= IsPixelBased ? pixelSize.Height : logicalSize.Height;

                if (DoubleUtil.GreaterThan(parentViewport.Y, 0))
                {
                    //
                    // Viewport is after the start of this panel
                    //

                    if (IsPixelBased && DoubleUtil.GreaterThan(pixelSize.Height, parentViewport.Y))
                    {
                        //
                        // Header straddles the start edge of the viewport
                        //

                        sizeAfterStartViewportEdge = pixelSize.Height - parentViewport.Y;
                        sizeBeforeStartViewportEdge = pixelSize.Height - sizeAfterStartViewportEdge;

                        viewport.Height = Math.Max(viewport.Height - sizeAfterStartViewportEdge, 0);

                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheBeforeSize = Math.Max(cacheBeforeSize - sizeBeforeStartViewportEdge, 0);
                        }
                        else
                        {
                            cacheBeforeSize = Math.Max(cacheBeforeSize - Math.Floor(logicalSize.Height * sizeBeforeStartViewportEdge / pixelSize.Height), 0);
                        }
                    }
                    else
                    {
                        //
                        // Header is completely before the start edge of the viewport. We do not need to
                        // adjust the cacheBefore size in this case because the cacheBefore is populated
                        // bottom up and we cant really be certain that the header will infact lie within the
                        // cacheBefore region.
                        //
                    }
                }
                else
                {
                    //
                    // Viewport is at or before the start of this panel
                    //

                    if (DoubleUtil.GreaterThan(parentViewport.Height, 0))
                    {
                        if (DoubleUtil.GreaterThanOrClose(parentViewport.Height, pixelSize.Height))
                        {
                            //
                            // Header is completely within the viewport
                            //

                            viewport.Height = Math.Max(0, parentViewport.Height - pixelSize.Height);
                        }
                        else
                        {
                            //
                            // Header straddles the end edge of the viewport
                            //

                            sizeBeforeEndViewportEdge = parentViewport.Height;
                            sizeAfterEndViewportEdge = pixelSize.Height - sizeBeforeEndViewportEdge;

                            viewport.Height = 0;

                            if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                            {
                                cacheAfterSize = Math.Max(cacheAfterSize - sizeAfterEndViewportEdge, 0);
                            }
                            else
                            {
                                cacheAfterSize = Math.Max(cacheAfterSize - Math.Floor(logicalSize.Height * sizeAfterEndViewportEdge / pixelSize.Height), 0);
                            }
                        }
                    }
                    else
                    {
                        //
                        // Header is completely after the end edge of the viewport
                        //

                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheAfterSize = Math.Max(cacheAfterSize - pixelSize.Height, 0);
                        }
                        else
                        {
                            cacheAfterSize = Math.Max(cacheAfterSize - logicalSize.Height, 0);
                        }
                    }
                }
            }

            cacheLength = new VirtualizationCacheLength(cacheBeforeSize, cacheAfterSize);
        }
Example #6
0
 /// <summary>
 /// Adjusts viewport to accomodate the items.
 /// </summary>
 private void AdjustNonScrollingViewportForItems(IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
                                                     ref Rect viewport,
                                                     ref VirtualizationCacheLength cacheLength,
                                                     ref VirtualizationCacheLengthUnit cacheLengthUnit)
 {
     bool forHeader = false;
     AdjustNonScrollingViewport(virtualizationInfoProvider, ref viewport, ref cacheLength, ref cacheLengthUnit, forHeader);
 }
Example #7
0
        /// <summary>
        /// Extends the viewport to include the cacheSizeBeforeViewport and cacheSizeAfterViewport.
        /// </summary>
        private Rect ExtendViewport(
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            bool isHorizontal,
            Rect viewport,
            VirtualizationCacheLength cacheLength,
            VirtualizationCacheLengthUnit cacheUnit,
            Size stackPixelSizeInCacheBeforeViewport,
            Size stackLogicalSizeInCacheBeforeViewport,
            Size stackPixelSizeInCacheAfterViewport,
            Size stackLogicalSizeInCacheAfterViewport,
            Size stackPixelSize,
            Size stackLogicalSize,
            ref int itemsInExtendedViewportCount)
        {
            Debug.Assert(cacheUnit != VirtualizationCacheLengthUnit.Page, "Page cacheUnit is not expected here.");

            double pixelSize, pixelSizeBeforeViewport, pixelSizeAfterViewport;
            double logicalSize, logicalSizeBeforeViewport, logicalSizeAfterViewport;
            Rect extendedViewport = viewport;

            if (isHorizontal)
            {
                double approxSizeOfLogicalUnit = (DoubleUtil.GreaterThan(_previousStackPixelSizeInViewport.Width, 0.0) && DoubleUtil.GreaterThan(_previousStackLogicalSizeInViewport.Width, 0.0)) ?
                    _previousStackPixelSizeInViewport.Width / _previousStackLogicalSizeInViewport.Width : ScrollViewer._scrollLineDelta;

                pixelSize = stackPixelSize.Width;
                logicalSize = stackLogicalSize.Width;

                if (MeasureCaches)
                {
                    pixelSizeBeforeViewport = stackPixelSizeInCacheBeforeViewport.Width;
                    pixelSizeAfterViewport = stackPixelSizeInCacheAfterViewport.Width;
                    logicalSizeBeforeViewport = stackLogicalSizeInCacheBeforeViewport.Width;
                    logicalSizeAfterViewport = stackLogicalSizeInCacheAfterViewport.Width;
                }
                else
                {
                    pixelSizeBeforeViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheBeforeViewport * approxSizeOfLogicalUnit : cacheLength.CacheBeforeViewport;
                    pixelSizeAfterViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheAfterViewport * approxSizeOfLogicalUnit : cacheLength.CacheAfterViewport;
                    logicalSizeBeforeViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheBeforeViewport : cacheLength.CacheBeforeViewport / approxSizeOfLogicalUnit;
                    logicalSizeAfterViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheAfterViewport : cacheLength.CacheAfterViewport / approxSizeOfLogicalUnit;

                    if (IsPixelBased)
                    {
                        pixelSizeBeforeViewport = Math.Max(pixelSizeBeforeViewport, Math.Abs(_viewport.X - _extendedViewport.X));
                    }
                    else
                    {
                        logicalSizeBeforeViewport = Math.Max(logicalSizeBeforeViewport, Math.Abs(_viewport.X - _extendedViewport.X));
                    }
                }

                if (IsPixelBased)
                {
                    if (!IsScrolling && virtualizationInfoProvider != null &&
                        IsViewportEmpty(isHorizontal, extendedViewport) &&
                        DoubleUtil.GreaterThan(pixelSizeBeforeViewport, 0))
                    {
                        //
                        // If this is a GroupItem or a TreeViewItem that is completely above the viewport,
                        // then the CacheBeforeViewport allways designates the distance of the bottom of
                        // this panel from the top of the extendedViewport. Hence this computation for the offset.
                        //

                        extendedViewport.X = pixelSize - pixelSizeBeforeViewport;
                    }
                    else
                    {
                        extendedViewport.X -= pixelSizeBeforeViewport;
                    }

                    extendedViewport.Width += pixelSizeBeforeViewport + pixelSizeAfterViewport;

                    //
                    // Once again coerce the extended viewport dimensions to be within valid range.
                    //
                    if (IsScrolling)
                    {
                        if (DoubleUtil.LessThan(extendedViewport.X, 0.0))
                        {
                            extendedViewport.Width = Math.Max(extendedViewport.Width + extendedViewport.X, 0.0);
                            extendedViewport.X = 0.0;
                        }

                        if (DoubleUtil.GreaterThan(extendedViewport.X + extendedViewport.Width, _scrollData._extent.Width))
                        {
                            extendedViewport.Width = _scrollData._extent.Width - extendedViewport.X;
                        }
                    }
                }
                else
                {
                    if (!IsScrolling && virtualizationInfoProvider != null &&
                        IsViewportEmpty(isHorizontal, extendedViewport) &&
                        DoubleUtil.GreaterThan(pixelSizeBeforeViewport, 0))
                    {
                        //
                        // If this is a GroupItem or a TreeViewItem that is completely above the viewport,
                        // then the CacheBeforeViewport allways designates the distance of the bottom of
                        // this panel from the top of the extendedViewport. Hence this computation for the offset.
                        //

                        extendedViewport.X = logicalSize - logicalSizeBeforeViewport;
                    }
                    else
                    {
                        extendedViewport.X -= logicalSizeBeforeViewport;
                    }

                    extendedViewport.Width += pixelSizeBeforeViewport + pixelSizeAfterViewport;

                    if (IsScrolling)
                    {
                        if (DoubleUtil.LessThan(extendedViewport.X, 0.0))
                        {
                            extendedViewport.Width = Math.Max(extendedViewport.Width / approxSizeOfLogicalUnit + extendedViewport.X, 0.0) * approxSizeOfLogicalUnit;
                            extendedViewport.X = 0.0;
                        }

                        if (DoubleUtil.GreaterThan(extendedViewport.X + extendedViewport.Width / approxSizeOfLogicalUnit, _scrollData._extent.Width))
                        {
                            extendedViewport.Width = (_scrollData._extent.Width - extendedViewport.X) * approxSizeOfLogicalUnit;
                        }
                    }
                }
            }
            else
            {
                double approxSizeOfLogicalUnit = (DoubleUtil.GreaterThan(_previousStackPixelSizeInViewport.Height, 0.0) && DoubleUtil.GreaterThan(_previousStackLogicalSizeInViewport.Height, 0.0)) ?
                    _previousStackPixelSizeInViewport.Height / _previousStackLogicalSizeInViewport.Height : ScrollViewer._scrollLineDelta;

                pixelSize = stackPixelSize.Height;
                logicalSize = stackLogicalSize.Height;

                if (MeasureCaches)
                {
                    pixelSizeBeforeViewport = stackPixelSizeInCacheBeforeViewport.Height;
                    pixelSizeAfterViewport = stackPixelSizeInCacheAfterViewport.Height;
                    logicalSizeBeforeViewport = stackLogicalSizeInCacheBeforeViewport.Height;
                    logicalSizeAfterViewport = stackLogicalSizeInCacheAfterViewport.Height;
                }
                else
                {
                    pixelSizeBeforeViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheBeforeViewport * approxSizeOfLogicalUnit : cacheLength.CacheBeforeViewport;
                    pixelSizeAfterViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheAfterViewport * approxSizeOfLogicalUnit : cacheLength.CacheAfterViewport;
                    logicalSizeBeforeViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheBeforeViewport : cacheLength.CacheBeforeViewport / approxSizeOfLogicalUnit;
                    logicalSizeAfterViewport = (cacheUnit == VirtualizationCacheLengthUnit.Item) ? cacheLength.CacheAfterViewport : cacheLength.CacheAfterViewport / approxSizeOfLogicalUnit;

                    if (IsPixelBased)
                    {
                        pixelSizeBeforeViewport = Math.Max(pixelSizeBeforeViewport, Math.Abs(_viewport.Y - _extendedViewport.Y));
                    }
                    else
                    {
                        logicalSizeBeforeViewport = Math.Max(logicalSizeBeforeViewport, Math.Abs(_viewport.Y - _extendedViewport.Y));
                    }
                }

                if (IsPixelBased)
                {
                    if (!IsScrolling && virtualizationInfoProvider != null &&
                        IsViewportEmpty(isHorizontal, extendedViewport) &&
                        DoubleUtil.GreaterThan(pixelSizeBeforeViewport, 0))
                    {
                        //
                        // If this is a GroupItem or a TreeViewItem that is completely above the viewport,
                        // then the CacheBeforeViewport allways designates the distance of the bottom of
                        // this panel from the top of the extendedViewport. Hence this computation for the offset.
                        //

                        extendedViewport.Y = pixelSize - pixelSizeBeforeViewport;
                    }
                    else
                    {
                        extendedViewport.Y -= pixelSizeBeforeViewport;
                    }

                    extendedViewport.Height += pixelSizeBeforeViewport + pixelSizeAfterViewport;

                    //
                    // Once again coerce the extended viewport dimensions to be within valid range.
                    //
                    if (IsScrolling)
                    {
                        if (DoubleUtil.LessThan(extendedViewport.Y, 0.0))
                        {
                            extendedViewport.Height = Math.Max(extendedViewport.Height + extendedViewport.Y, 0.0);
                            extendedViewport.Y = 0.0;
                        }

                        if (DoubleUtil.GreaterThan(extendedViewport.Y + extendedViewport.Height, _scrollData._extent.Height))
                        {
                            extendedViewport.Height = _scrollData._extent.Height - extendedViewport.Y;
                        }
                    }
                }
                else
                {
                    if (!IsScrolling && virtualizationInfoProvider != null &&
                        IsViewportEmpty(isHorizontal, extendedViewport) &&
                        DoubleUtil.GreaterThan(pixelSizeBeforeViewport, 0))
                    {
                        //
                        // If this is a GroupItem or a TreeViewItem that is completely above the viewport,
                        // then the CacheBeforeViewport allways designates the distance of the bottom of
                        // this panel from the top of the extendedViewport. Hence this computation for the offset.
                        //

                        extendedViewport.Y = logicalSize - logicalSizeBeforeViewport;
                    }
                    else
                    {
                        extendedViewport.Y -= logicalSizeBeforeViewport;
                    }

                    extendedViewport.Height += pixelSizeBeforeViewport + pixelSizeAfterViewport;

                    if (IsScrolling)
                    {
                        if (DoubleUtil.LessThan(extendedViewport.Y, 0.0))
                        {
                            extendedViewport.Height = Math.Max(extendedViewport.Height / approxSizeOfLogicalUnit + extendedViewport.Y, 0.0) * approxSizeOfLogicalUnit;
                            extendedViewport.Y = 0.0;
                        }

                        if (DoubleUtil.GreaterThan(extendedViewport.Y + extendedViewport.Height / approxSizeOfLogicalUnit, _scrollData._extent.Height))
                        {
                            extendedViewport.Height = (_scrollData._extent.Height - extendedViewport.Y) * approxSizeOfLogicalUnit;
                        }
                    }
                }
            }

            if (MeasureCaches)
            {
                itemsInExtendedViewportCount = _actualItemsInExtendedViewportCount;
            }
            else
            {
                double factor = Math.Max(1.0, isHorizontal ? extendedViewport.Width / viewport.Width : extendedViewport.Height / viewport.Height);
                int calcItemsInExtendedViewportCount = (int)Math.Ceiling(factor * _actualItemsInExtendedViewportCount);
                itemsInExtendedViewportCount = Math.Max(calcItemsInExtendedViewportCount, itemsInExtendedViewportCount);
            }

            return extendedViewport;
        }
Example #8
0
        /// <summary>
        /// Initializes the viewport for this panel.
        /// </summary>
        private void InitializeViewport(
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            bool isHorizontal,
            Size constraint,
            ref Rect viewport,
            ref VirtualizationCacheLength cacheSize,
            ref VirtualizationCacheLengthUnit cacheUnit,
            out Rect extendedViewport)
        {

            Size extent = new Size();

            if (IsScrolling)
            {
                //
                // We're the top level scrolling panel. Fetch the offset from the _scrollData.
                //

                Size size;
                double offsetX, offsetY;
                Size viewportSize;

                size = constraint;
                offsetX = _scrollData._offset.X;
                offsetY = _scrollData._offset.Y;
                extent = _scrollData._extent;
                viewportSize = _scrollData._viewport;

                if (!IsScrollActive || IgnoreMaxDesiredSize)
                {
                    _scrollData._maxDesiredSize = new Size();
                }

                if (IsPixelBased)
                {
                    viewport = new Rect(offsetX, offsetY, size.Width, size.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                }
                else
                {
                    viewport = new Rect(offsetX, offsetY, viewportSize.Width, viewportSize.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                    viewport.Size = size;
                }

                if (IsVirtualizing)
                {
                    cacheSize = VirtualizingStackPanel.GetCacheLength(this);
                    cacheUnit = VirtualizingStackPanel.GetCacheLengthUnit(this);

                    if (DoubleUtil.GreaterThan(cacheSize.CacheBeforeViewport, 0) ||
                        DoubleUtil.GreaterThan(cacheSize.CacheAfterViewport, 0))
                    {
                        if (!MeasureCaches)
                        {
                            WasLastMeasurePassAnchored = (_firstContainerInViewport != null) || (_bringIntoViewLeafContainer != null);

                            DispatcherOperation measureCachesOperation = MeasureCachesOperationField.GetValue(this);
                            if (measureCachesOperation == null)
                            {
                                measureCachesOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                    (Action)delegate()
                                    {
                                        try
                                        {
                                            MeasureCachesOperationField.ClearValue(this);

                                            MeasureCaches = true;

                                            if (WasLastMeasurePassAnchored)
                                            {
                                                SetAnchorInformation(isHorizontal);
                                            }

                                            InvalidateMeasure();
                                            UpdateLayout();
                                        }
                                        finally
                                        {
                                            MeasureCaches = false;

                                            // If there is a pending anchor operation that got registered in
                                            // the current pass, we dont want to clear the IsScrollActive flag.
                                            // We should allow that measure pass to also settle and then clear
                                            // the flag.

                                            DispatcherOperation anchoredInvalidateMeasureOperation = AnchoredInvalidateMeasureOperationField.GetValue(this);
                                            if (anchoredInvalidateMeasureOperation == null)
                                            {
                                                IsScrollActive = false;
                                            }
                                        }
                                    });

                                MeasureCachesOperationField.SetValue(this, measureCachesOperation);
                            }
                        }
                    }
                    else if (IsScrollActive)
                    {
                        DispatcherOperation clearIsScrollActiveOperation = ClearIsScrollActiveOperationField.GetValue(this);
                        if (clearIsScrollActiveOperation == null)
                        {
                            clearIsScrollActiveOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                (Action)delegate()
                                {
                                    ClearIsScrollActiveOperationField.ClearValue(this);
                                    IsScrollActive = false;
                                });

                            ClearIsScrollActiveOperationField.SetValue(this, clearIsScrollActiveOperation);
                        }
                    }

                    NormalizeCacheLength(isHorizontal, viewport, ref cacheSize, ref cacheUnit);
                }
                else
                {
                    cacheSize = new VirtualizationCacheLength(
                        Double.PositiveInfinity,
                        IsViewportEmpty(isHorizontal, viewport) ?
                        0.0 :
                        Double.PositiveInfinity);
                    cacheUnit = VirtualizationCacheLengthUnit.Pixel;

                    ClearAsyncOperations();
                }
            }
            else if (virtualizationInfoProvider != null)
            {
                //
                // Adjust the viewport offset for a non scrolling panel to account for the HeaderSize
                // when virtualizing.
                //
                HierarchicalVirtualizationConstraints virtualizationConstraints = virtualizationInfoProvider.Constraints;
                viewport = virtualizationConstraints.Viewport;
                cacheSize = virtualizationConstraints.CacheLength;
                cacheUnit = virtualizationConstraints.CacheLengthUnit;
                MeasureCaches = virtualizationInfoProvider.InBackgroundLayout;

                AdjustNonScrollingViewportForHeader(virtualizationInfoProvider, ref viewport, ref cacheSize, ref cacheUnit);
            }
            else
            {
                viewport = new Rect(0, 0, constraint.Width, constraint.Height);

                if (isHorizontal)
                {
                    viewport.Width = Double.PositiveInfinity;
                }
                else
                {
                    viewport.Height = Double.PositiveInfinity;
                }
            }

            // Adjust extendedViewport

            extendedViewport = _extendedViewport;

            if (isHorizontal)
            {
                extendedViewport.X += viewport.X - _viewport.X;
            }
            else
            {
                extendedViewport.Y += viewport.Y - _viewport.Y;
            }
        }
Example #9
0
        /// <summary>
        /// Initializes the owner and interfaces for the virtualization services it supports.
        /// </summary>
        private void GetOwners(
            bool shouldSetVirtualizationState,
            bool isHorizontal,
            out ItemsControl itemsControl,
            out GroupItem groupItem,
            out IContainItemStorage itemStorageProvider,
            out IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            out object parentItem,
            out IContainItemStorage parentItemStorageProvider,
            out bool mustDisableVirtualization)
        {
            groupItem = null;
            parentItem = null;
            parentItemStorageProvider = null;

            bool isScrolling = IsScrolling;

            mustDisableVirtualization = isScrolling ? MustDisableVirtualization : false;

            ItemsControl parentItemsControl = null;
            DependencyObject itemsOwner = ItemsControl.GetItemsOwnerInternal(this, out itemsControl);
            if (itemsOwner != itemsControl)
            {
                groupItem = itemsOwner as GroupItem;
                parentItem = itemsControl.ItemContainerGenerator.ItemFromContainer(groupItem);
            }
            else if (!isScrolling)
            {
                parentItemsControl = ItemsControl.GetItemsOwnerInternal(VisualTreeHelper.GetParent(itemsControl)) as ItemsControl;
                if (parentItemsControl != null)
                {
                    parentItem = parentItemsControl.ItemContainerGenerator.ItemFromContainer(itemsControl);
                }
                else
                {
                    parentItem = this;
                }
            }
            else
            {
                parentItem = this;
            }

            itemStorageProvider = itemsOwner as IContainItemStorage;
            virtualizationInfoProvider = null;
            parentItemStorageProvider = (IsVSP45Compat || isScrolling || itemsOwner == null) ? null :
                ItemsControl.GetItemsOwnerInternal(VisualTreeHelper.GetParent(itemsOwner)) as IContainItemStorage;

            if (groupItem != null)
            {
                virtualizationInfoProvider = GetVirtualizingProvider(groupItem);
                mustDisableVirtualization = virtualizationInfoProvider != null ? virtualizationInfoProvider.MustDisableVirtualization : false;
            }
            else if (!isScrolling)
            {
                virtualizationInfoProvider = GetVirtualizingProvider(itemsControl);
                mustDisableVirtualization = virtualizationInfoProvider != null ? virtualizationInfoProvider.MustDisableVirtualization : false;
            }

            if (shouldSetVirtualizationState)
            {
                // this is a good opportunity to set up tracing, if requested
                if (ScrollTracer.IsEnabled && !ScrollTracer.IsConfigured(this))
                {
                    ScrollTracer.ConfigureTracing(this, itemsOwner, parentItem, itemsControl);
                }

                //
                // Synchronize properties such as IsVirtualizing, IsRecycling & IsPixelBased
                //
                SetVirtualizationState(itemStorageProvider, itemsControl, mustDisableVirtualization);
            }
        }
Example #10
0
 // Token: 0x060064DE RID: 25822 RVA: 0x001C5000 File Offset: 0x001C3200
 internal static void ClearVirtualizingElement(IHierarchicalVirtualizationAndScrollInfo virtualizingElement)
 {
     virtualizingElement.ItemDesiredSizes          = default(HierarchicalVirtualizationItemDesiredSizes);
     virtualizingElement.MustDisableVirtualization = false;
 }
Example #11
0
        }// *** End DEAD CODE ***

        private void GetSizesForChildWithInset(
            bool isHorizontal,
            bool isChildHorizontal,
            bool isBeforeFirstItem,
            bool isAfterLastItem,
            IHierarchicalVirtualizationAndScrollInfo virtualizingChild,
            Size childDesiredSize,
            Rect childViewport,
            VirtualizationCacheLength childCacheSize,
            VirtualizationCacheLengthUnit childCacheUnit,
            out Size childPixelSize,
            out Size childPixelSizeInViewport,
            out Size childPixelSizeInCacheBeforeViewport,
            out Size childPixelSizeInCacheAfterViewport,
            out Size childLogicalSize,
            out Size childLogicalSizeInViewport,
            out Size childLogicalSizeInCacheBeforeViewport,
            out Size childLogicalSizeInCacheAfterViewport)
        {
            // set childPixelSize to childDesiredSize directly.   Ideally this should
            // be the same as adding the contributions from the items panel and
            // the front and back insets, as indicated by commented-out lines below,
            // but this isn't true when the inset is merely an estimate (i.e.
            // before the child has been arranged) - contributions from margins,
            // border thickness, etc. between the items panel and the virtualizingChild
            // are not yet accounted for.  The childDesiredSize is more accurate,
            // so we use that.
            childPixelSize = childDesiredSize;
            childPixelSizeInViewport = new Size();
            childPixelSizeInCacheBeforeViewport = new Size();
            childPixelSizeInCacheAfterViewport = new Size();

            childLogicalSize = new Size();
            childLogicalSizeInViewport = new Size();
            childLogicalSizeInCacheBeforeViewport = new Size();
            childLogicalSizeInCacheAfterViewport = new Size();

            HierarchicalVirtualizationItemDesiredSizes itemDesiredSizes =
                (virtualizingChild != null) ? virtualizingChild.ItemDesiredSizes
                                            : new HierarchicalVirtualizationItemDesiredSizes();

            // the interesting case is when there is nested virtualization.  It's not
            // enough to test whether virtualizingChild is non-null;  the child
            // may not have done any virtualization (eg. because its ItemsHost
            // is not a VSP).  Instead, test whether its ItemsHost recorded a
            // nonzero extent.
            if ((!isHorizontal &&  (itemDesiredSizes.PixelSize.Height > 0 ||
                                    itemDesiredSizes.LogicalSize.Height > 0)) ||
                ( isHorizontal &&  (itemDesiredSizes.PixelSize.Width > 0 ||
                                    itemDesiredSizes.LogicalSize.Width > 0)))
            {
                // itemDesiredSizes gives the contribution from the nested panel.
              //StackSizes(isHorizontal, ref childPixelSize, itemDesiredSizes.PixelSize); (omitted - see comment at initialization)
                StackSizes(isHorizontal, ref childPixelSizeInCacheBeforeViewport, itemDesiredSizes.PixelSizeBeforeViewport);
                StackSizes(isHorizontal, ref childPixelSizeInViewport, itemDesiredSizes.PixelSizeInViewport);
                StackSizes(isHorizontal, ref childPixelSizeInCacheAfterViewport, itemDesiredSizes.PixelSizeAfterViewport);

                StackSizes(isHorizontal, ref childLogicalSize, itemDesiredSizes.LogicalSize);
                StackSizes(isHorizontal, ref childLogicalSizeInCacheBeforeViewport, itemDesiredSizes.LogicalSizeBeforeViewport);
                StackSizes(isHorizontal, ref childLogicalSizeInViewport, itemDesiredSizes.LogicalSizeInViewport);
                StackSizes(isHorizontal, ref childLogicalSizeInCacheAfterViewport, itemDesiredSizes.LogicalSizeAfterViewport);

                // Now add the contributions from the inset.  First decide whether
                // the child's item belongs to the front or back inset
                Thickness inset = GetItemsHostInsetForChild(virtualizingChild);
                bool isHeaderBeforeItems = IsHeaderBeforeItems(isHorizontal, virtualizingChild as FrameworkElement, ref inset);

                // Add contributions from the front inset.
                Size frontPixelSize = isHorizontal ? new Size(Math.Max(inset.Left,0), childDesiredSize.Height)
                                                   : new Size(childDesiredSize.Width, Math.Max(inset.Top, 0));
                Size frontLogicalSize = isHeaderBeforeItems ? new Size(1,1) : new Size(0,0);

              //StackSizes(isHorizontal, ref childPixelSize, frontPixelSize); (omitted - see comment at initialization)
                StackSizes(isHorizontal, ref childLogicalSize, frontLogicalSize);
                GetSizesForChildIntersectingTheViewport(isHorizontal, isChildHorizontal,
                    frontPixelSize, frontLogicalSize,
                    childViewport,
                    ref childPixelSizeInViewport, ref childLogicalSizeInViewport,
                    ref childPixelSizeInCacheBeforeViewport, ref childLogicalSizeInCacheBeforeViewport,
                    ref childPixelSizeInCacheAfterViewport, ref childLogicalSizeInCacheAfterViewport);

                // Add contributions from the back inset.
                Size backPixelSize = isHorizontal ? new Size(Math.Max(inset.Right,0), childDesiredSize.Height)
                                                   : new Size(childDesiredSize.Width, Math.Max(inset.Bottom,0));
                Size backLogicalSize = isHeaderBeforeItems ? new Size(0,0) : new Size(1,1);

              //StackSizes(isHorizontal, ref childPixelSize, backPixelSize); (omitted - see comment at initialization)
                StackSizes(isHorizontal, ref childLogicalSize, backLogicalSize);

                // before calling the helper, adjust the viewport to account for
                // the contributions we've just made
                Rect adjustedChildViewport = childViewport;
                if (isHorizontal)
                {
                    adjustedChildViewport.X -= IsPixelBased ? frontPixelSize.Width + itemDesiredSizes.PixelSize.Width
                                                            : frontLogicalSize.Width + itemDesiredSizes.LogicalSize.Width;
                    adjustedChildViewport.Width = Math.Max(0, adjustedChildViewport.Width - childPixelSizeInViewport.Width);
                }
                else
                {
                    adjustedChildViewport.Y -= IsPixelBased ? frontPixelSize.Height + itemDesiredSizes.PixelSize.Height
                                                            : frontLogicalSize.Height + itemDesiredSizes.LogicalSize.Height;
                    adjustedChildViewport.Height = Math.Max(0, adjustedChildViewport.Height - childPixelSizeInViewport.Height);
                }
                GetSizesForChildIntersectingTheViewport(isHorizontal, isChildHorizontal,
                    backPixelSize, backLogicalSize,
                    adjustedChildViewport,
                    ref childPixelSizeInViewport, ref childLogicalSizeInViewport,
                    ref childPixelSizeInCacheBeforeViewport, ref childLogicalSizeInCacheBeforeViewport,
                    ref childPixelSizeInCacheAfterViewport, ref childLogicalSizeInCacheAfterViewport);
            }
            else
            {
                // there was no nested virtualization.  The only contributions come
                // directly from the given child.

              //childPixelSize = childDesiredSize; (already done at initialization)
                childLogicalSize = new Size(1, 1);

                if (isBeforeFirstItem)
                {
                    childPixelSizeInCacheBeforeViewport = childDesiredSize;
                    childLogicalSizeInCacheBeforeViewport = new Size(DoubleUtil.GreaterThan(childPixelSizeInCacheBeforeViewport.Width, 0) ? 1 : 0,
                                                                     DoubleUtil.GreaterThan(childPixelSizeInCacheBeforeViewport.Height, 0) ? 1 : 0);
                }
                else if (isAfterLastItem)
                {
                    childPixelSizeInCacheAfterViewport = childDesiredSize;
                    childLogicalSizeInCacheAfterViewport = new Size(DoubleUtil.GreaterThan(childPixelSizeInCacheAfterViewport.Width, 0) ? 1 : 0,
                                                                    DoubleUtil.GreaterThan(childPixelSizeInCacheAfterViewport.Height, 0) ? 1 : 0);
                }
                else
                {
                    GetSizesForChildIntersectingTheViewport(
                        isHorizontal,
                        isChildHorizontal,
                        childPixelSize,
                        childLogicalSize,
                        childViewport,
                        ref childPixelSizeInViewport,
                        ref childLogicalSizeInViewport,
                        ref childPixelSizeInCacheBeforeViewport,
                        ref childLogicalSizeInCacheBeforeViewport,
                        ref childPixelSizeInCacheAfterViewport,
                        ref childLogicalSizeInCacheAfterViewport);
                }
            }
        }
Example #12
0
        private Thickness GetItemsHostInsetForChild(IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider, IContainItemStorage parentItemStorageProvider=null, object parentItem=null)
        {
            // This method is called in two ways:
            // 1) Before this panel has been measured.
            //      Args:  parentItemStorageProvider is non-null.
            //      This is called from AdjustNonScrollingViewportForInset, to
            //      get the viewport into the panel's coordinates.  We don't yet
            //      know the real inset, but the parentItemStorageProvider may
            //      have a last-known estimate.
            // 2) After this panel has been measured.
            //      Args: parentItemStorageProvider is null.
            //      This is called while measuring or arranging an ancestor panel,
            //      who needs to know the inset for this panel.  In this case,
            //      the inset is already stored on the container, either by an
            //      earlier query of type 1, or during this panel's arrange.

            FrameworkElement container = virtualizationInfoProvider as FrameworkElement;
            Debug.Assert(parentItemStorageProvider != null || container != null,
                "Caller of GetItemsHostInsetForChild must provide either an ItemsStorageProvider or a container");

            // type 2 - get the value directly from the container
            if (parentItemStorageProvider == null)
            {
                return (Thickness)container.GetValue(ItemsHostInsetProperty);
            }

            // type 1 - get the last-known inset
            Thickness inset = new Thickness();
            object box = parentItemStorageProvider.ReadItemValue(parentItem, ItemsHostInsetProperty);
            if (box != null)
            {
                inset = (Thickness)box;
            }
            else if ((box = container.ReadLocalValue(ItemsHostInsetProperty)) != DependencyProperty.UnsetValue)
            {
                // recycled container - use the recycled value
                inset = (Thickness)box;
            }
            else
            {
                // first-time, use header desired size as a guess.  This is correct
                // for the default container templates.   Even better guess - include
                // the container's margin.
                HierarchicalVirtualizationHeaderDesiredSizes headerDesiredSizes = virtualizationInfoProvider.HeaderDesiredSizes;
                Thickness margin = container.Margin;
                inset.Top = headerDesiredSizes.PixelSize.Height + margin.Top;
                inset.Left = headerDesiredSizes.PixelSize.Width + margin.Left;

                // store the value, for use by later queries of type 1
                parentItemStorageProvider.StoreItemValue(parentItem, ItemsHostInsetProperty, inset);
            }

            // store the value, for use by later queries of type 2
            container.SetValue(ItemsHostInsetProperty, inset);

            return inset;
        }
Example #13
0
        /// <summary>
        /// After a measure pass, compute the effective offset - taking into account
        /// changes to the average container size discovered during measure.  This
        /// is the inverse of the previous method - ComputeFirstItemInViewportIndexAndOffset -
        /// in the sense that it produces an offset that, if fed back into that method (with
        /// the revised average container sizes), will yield the same result obtained
        /// in the current measure pass.  That is, the same item will be selected
        /// as the first item, and likewise for its sub-items.
        /// </summary>
        private double ComputeEffectiveOffset(
            ref Rect viewport,
            DependencyObject firstContainer,
            int itemIndex,
            double firstItemOffset,
            IList items,
            IContainItemStorage itemStorageProvider,
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            bool isHorizontal,
            bool areContainersUniformlySized,
            double uniformOrAverageContainerSize)
        {
            if (firstContainer == null)
            {
                return -1.0;    // undefined if no children in view
            }

            Debug.Assert(itemIndex < items.Count, "index out of range");
            double oldOffset = isHorizontal ? viewport.X : viewport.Y;
            double newOffset;

            // start with the effective offset of the first item
            ComputeDistance(items, itemStorageProvider, isHorizontal,
                areContainersUniformlySized, uniformOrAverageContainerSize,
                0, itemIndex, out newOffset);

            // add the offset within the first item
            newOffset += (oldOffset - firstItemOffset);

            // if the item's container has recorded a substitute offset,
            // adjust newOffset by the same amount.   This has the effect of
            // giving the child panel the offset it wants the next time this
            // panel measures the child.
            List<Double> childOffsetList = EffectiveOffsetInformationField.GetValue(firstContainer);
            if (childOffsetList != null)
            {
                int count = childOffsetList.Count;
                newOffset += (childOffsetList[count-1] - childOffsetList[0]);
            }

            // record the answer (when not a top-level panel), for use by InitializeViewport.
            DependencyObject container = virtualizationInfoProvider as DependencyObject;
            if (container != null && oldOffset != newOffset)
            {
                // preserve the existing old offsets, if any, in case there are
                // multiple calls to measure this panel before the parent
                // adjusts to the change in our coordinate system, or calls from
                // a parent who set its own offset using an older offset from here
                List<Double> offsetList = EffectiveOffsetInformationField.GetValue(container);
                if (offsetList == null)
                {
                    offsetList = new List<Double>(2);
                    offsetList.Add(oldOffset);
                }

                offsetList.Add(newOffset);

                if (ScrollTracer.IsEnabled && ScrollTracer.IsTracing(this))
                {
                    object[] args = new object[offsetList.Count];
                    for (int i=0; i<offsetList.Count; ++i)
                    {
                        args[i] = offsetList[i];
                    }
                    ScrollTracer.Trace(this, ScrollTraceOp.StoreSubstOffset,
                        args);
                }

                EffectiveOffsetInformationField.SetValue(container, offsetList);
            }

            return newOffset;
        }
Example #14
0
        }// *** END DEAD CODE ***

        /// <summary>
        /// Adjusts viewport to accommodate the inset.
        /// </summary>
        private void AdjustNonScrollingViewportForInset(
            bool isHorizontal,
            object parentItem,
            IContainItemStorage parentItemStorageProvider,
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            ref Rect viewport,
            ref VirtualizationCacheLength cacheLength,
            ref VirtualizationCacheLengthUnit cacheUnit)
        {
            // Recall that a viewport-rect has location (X,Y) expressed in scroll units
            // (pixels or items), but size (Width,Height) expressed in pixels and
            // describing the available size - previous contributions have been
            // deducted.
            Rect parentViewport = viewport;
            FrameworkElement container = virtualizationInfoProvider as FrameworkElement;
            Thickness inset = GetItemsHostInsetForChild(virtualizationInfoProvider, parentItemStorageProvider, parentItem);
            bool isHeaderBeforeItems = IsHeaderBeforeItems(isHorizontal, container, ref inset);
            double cacheBeforeSize = cacheLength.CacheBeforeViewport;
            double cacheAfterSize = cacheLength.CacheAfterViewport;

            // offset the viewport by the inset, along the scrolling axis
            if (isHorizontal)
            {
                viewport.X -= IsPixelBased ? inset.Left : isHeaderBeforeItems ? 1 : 0;
            }
            else
            {
                viewport.Y -= IsPixelBased ? inset.Top : isHeaderBeforeItems ? 1 : 0;
            }

            if (isHorizontal)
            {
                if (DoubleUtil.GreaterThan(parentViewport.X, 0))
                {
                    // Viewport is after start of this container

                    if (DoubleUtil.GreaterThan(viewport.Width, 0))
                    {
                        // Viewport is not yet full - we're delving for the first
                        // container in the viewport.  We're moving forward, so
                        // do not contribute to cache-after (we won't know whether
                        // this container needs to contribute to cache-after until
                        // after measuring this panel).

                        if (IsPixelBased && DoubleUtil.GreaterThan(0, viewport.X))
                        {
                            // Viewport starts within the leading inset

                            // The inset is split in two pieces by the viewport leading edge.
                            // The first piece contributes to the cache-before;
                            // its width is parentViewport.X
                            if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                            {
                                cacheBeforeSize = Math.Max(0, cacheBeforeSize - parentViewport.X);
                            }

                            // The second piece contributes to the viewport itself;
                            // its width is (inset.Left - parentViewport.X) = -viewport.X
                            viewport.Width = Math.Max(0, viewport.Width + viewport.X);
                        }
                        else
                        {
                            // Viewport starts after the leading inset.

                            // The contributions due to this container cannot be
                            // determined yet.  These are (a) leading inset to
                            // cache-before, (b) trailing inset to viewport and/or
                            // cache-after.
                        }
                    }
                    else
                    {
                        // viewport is full (and starts after this container).
                        // We're filling the cache-before back-to-front.

                        // The trailing inset contributes to cache-before
                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheBeforeSize = Math.Max(0, cacheBeforeSize - inset.Right);
                        }
                        else if (!isHeaderBeforeItems)
                        {
                            cacheBeforeSize = Math.Max(0, cacheBeforeSize - 1);
                        }
                    }
                }

                else if (DoubleUtil.GreaterThan(viewport.Width, 0))
                {
                    // Viewport has available space (and starts before this container)
                    // We are filling the viewport front-to-back.

                    if (DoubleUtil.GreaterThanOrClose(viewport.Width, inset.Left))
                    {
                        // Viewport has room for the entire leading inset.

                        // Leading inset contributes to viewport
                        viewport.Width = Math.Max(0, viewport.Width - inset.Left);
                    }
                    else
                    {
                        // Leading inset exhausts the remaining available space.

                        // The inset is split into two pieces (by the viewport trailing edge).
                        // The second piece contributes to the cache-after;
                        // its width is (inset.Left - viewport.Width)
                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheAfterSize = Math.Max(0, cacheAfterSize - (inset.Left - viewport.Width));
                        }

                        // The first piece contributes to the viewport itself;
                        // its width is viewport.Width (enough to decrease available width to zero)
                        viewport.Width = 0;
                    }
                }

                else
                {
                    // Viewport has no available space (and starts before this container).
                    // We are filling the cache-after front-to-back.

                    // The leading inset contributes to cache-after
                    if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                    {
                        cacheAfterSize = Math.Max(0, cacheAfterSize - inset.Left);
                    }
                    else if (isHeaderBeforeItems)
                    {
                        cacheAfterSize = Math.Max(0, cacheAfterSize - 1);
                    }
                }
            }
            else    // scroll axis is vertical
            {
                if (DoubleUtil.GreaterThan(parentViewport.Y, 0))
                {
                    // Viewport is after start of this container

                    if (DoubleUtil.GreaterThan(viewport.Height, 0))
                    {
                        // Viewport is not yet full - we're delving for the first
                        // container in the viewport.  We're moving forward, so
                        // do not contribute to cache-after (we won't know whether
                        // this container needs to contribute to cache-after until
                        // after measuring this panel).

                        if (IsPixelBased && DoubleUtil.GreaterThan(0, viewport.Y))
                        {
                            // Viewport starts within the leading inset

                            // The inset is split in two pieces by the viewport leading edge.
                            // The first piece contributes to the cache-before;
                            // its height is parentViewport.Y
                            if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                            {
                                cacheBeforeSize = Math.Max(0, cacheBeforeSize - parentViewport.Y);
                            }

                            // The second piece contributes to the viewport itself;
                            // its height is (inset.Top - parentViewport.Y) = -viewport.Y
                            viewport.Height = Math.Max(0, viewport.Height + viewport.Y);
                        }
                        else
                        {
                            // Viewport starts after the leading inset.

                            // The contributions due to this container cannot be
                            // determined yet.  These are (a) leading inset to
                            // cache-before, (b) trailing inset to viewport and/or
                            // cache-after.
                        }
                    }
                    else
                    {
                        // viewport is full (and starts after this container).
                        // We're filling the cache-before back-to-front.

                        // The trailing inset contributes to cache-before
                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheBeforeSize = Math.Max(0, cacheBeforeSize - inset.Bottom);
                        }
                        else if (!isHeaderBeforeItems)
                        {
                            cacheBeforeSize = Math.Max(0, cacheBeforeSize - 1);
                        }
                    }
                }

                else if (DoubleUtil.GreaterThan(viewport.Height, 0))
                {
                    // Viewport has available space (and starts before this container)
                    // We are filling the viewport front-to-back.

                    if (DoubleUtil.GreaterThanOrClose(viewport.Height, inset.Top))
                    {
                        // Viewport has room for the entire leading inset.

                        // Leading inset contributes to viewport
                        viewport.Height = Math.Max(0, viewport.Height - inset.Top);
                    }
                    else
                    {
                        // Leading inset exhausts the remaining available space.

                        // The inset is split into two pieces (by the viewport trailing edge).
                        // The second piece contributes to the cache-after;
                        // its height is (inset.Top - viewport.Height)
                        if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                        {
                            cacheAfterSize = Math.Max(0, cacheAfterSize - (inset.Top - viewport.Height));
                        }

                        // The first piece contributes to the viewport itself;
                        // its height is viewport.Height (enough to decrease available height to zero)
                        viewport.Height = 0;
                    }
                }

                else
                {
                    // Viewport has no available space (and starts before this container).
                    // We are filling the cache-after front-to-back.

                    // The leading inset contributes to cache-after
                    if (cacheUnit == VirtualizationCacheLengthUnit.Pixel)
                    {
                        cacheAfterSize = Math.Max(0, cacheAfterSize - inset.Top);
                    }
                    else if (isHeaderBeforeItems)
                    {
                        cacheAfterSize = Math.Max(0, cacheAfterSize - 1);
                    }
                }
            }

            // apply the cache adjustment
            cacheLength = new VirtualizationCacheLength(cacheBeforeSize, cacheAfterSize);
        }
Example #15
0
        /// <summary>
        /// Initializes the viewport for this panel.
        /// </summary>
        private void InitializeViewport(
            object parentItem,
            IContainItemStorage parentItemStorageProvider,
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            bool isHorizontal,
            Size constraint,
            ref Rect viewport,
            ref VirtualizationCacheLength cacheSize,
            ref VirtualizationCacheLengthUnit cacheUnit,
            out Rect extendedViewport)
        {

            Size extent = new Size();
            bool isVSP45Compat = IsVSP45Compat;

            if (IsScrolling)
            {
                //
                // We're the top level scrolling panel. Fetch the offset from the _scrollData.
                //

                Size size;
                double offsetX, offsetY;
                Size viewportSize;

                size = constraint;
                offsetX = _scrollData._offset.X;
                offsetY = _scrollData._offset.Y;
                extent = _scrollData._extent;
                viewportSize = _scrollData._viewport;

                if (!IsScrollActive || IgnoreMaxDesiredSize)
                {
                    _scrollData._maxDesiredSize = new Size();
                }

                if (IsPixelBased)
                {
                    viewport = new Rect(offsetX, offsetY, size.Width, size.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                }
                else
                {
                    viewport = new Rect(offsetX, offsetY, viewportSize.Width, viewportSize.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                    viewport.Size = size;
                }

                if (IsVirtualizing)
                {
                    cacheSize = VirtualizingStackPanel.GetCacheLength(this);
                    cacheUnit = VirtualizingStackPanel.GetCacheLengthUnit(this);

                    if (DoubleUtil.GreaterThan(cacheSize.CacheBeforeViewport, 0) ||
                        DoubleUtil.GreaterThan(cacheSize.CacheAfterViewport, 0))
                    {
                        if (!MeasureCaches)
                        {
                            WasLastMeasurePassAnchored = (_firstContainerInViewport != null) || (_bringIntoViewLeafContainer != null);

                            DispatcherOperation measureCachesOperation = MeasureCachesOperationField.GetValue(this);
                            if (measureCachesOperation == null)
                            {
                                Action measureCachesAction = null;
                                int retryCount = 3;
                                measureCachesAction = (Action)delegate()
                                    {
                                        Debug.Assert(retryCount >=0, "retry MeasureCaches too often");
                                        bool isLayoutDirty = (0 < retryCount--) && (MeasureDirty || ArrangeDirty);
                                        try
                                        {
                                            if (isVSP45Compat || !isLayoutDirty)
                                            {
                                                MeasureCachesOperationField.ClearValue(this);

                                                MeasureCaches = true;

                                                if (WasLastMeasurePassAnchored)
                                                {
                                                    SetAnchorInformation(isHorizontal);
                                                }

                                                InvalidateMeasure();
                                                UpdateLayout();
                                            }
                                        }
                                        finally
                                        {
                                            // check whether UpdateLayout finished the job
                                            isLayoutDirty = isLayoutDirty ||
                                                    ((0 < retryCount) && (MeasureDirty || ArrangeDirty));
                                            if (!isVSP45Compat && isLayoutDirty)
                                            {
                                                // try the measure-cache pass again later.
                                                // Note that we only do this when:
                                                // 1. this VSP's layout is dirty, either because
                                                //    a. it was dirty to begin with so we
                                                //       skipped UpdateLayout, or
                                                //    b. UpdateLayout ran, but left this VSP's
                                                //       layout dirty.
                                                // 2. we haven't run out of retries
                                                // 3. we're not in 4.5-compat mode
                                                //
                                                // (1) can happen if layout times out and moves to
                                                //     background.
                                                // (2) protects against loops when an app calls
                                                //     VSP.Measure directly, outside of the normal
                                                //     layout system (real appps don't do this,
                                                //     but test code does - it happens in the DrtXaml test).
                                                // (3) preserves compat with 4.5RTM, where the
                                                //     "move to background" situation led to an
                                                //     infinite loop.
                                                MeasureCachesOperationField.SetValue(this,
                                                    Dispatcher.BeginInvoke(DispatcherPriority.Background, measureCachesAction));
                                            }

                                            MeasureCaches = false;

                                            // If there is a pending anchor operation that got registered in
                                            // the current pass, or if layout didn't finish, we don't want to
                                            // clear the IsScrollActive flag.
                                            // We should allow that measure pass to also settle and then clear
                                            // the flag.

                                            DispatcherOperation anchoredInvalidateMeasureOperation = AnchoredInvalidateMeasureOperationField.GetValue(this);
                                            if (anchoredInvalidateMeasureOperation == null && (isVSP45Compat || !isLayoutDirty))
                                            {
                                                if (isVSP45Compat)
                                                {
                                                    IsScrollActive = false;
                                                }
                                                else if (IsScrollActive)
                                                {
                                                    // keep IsScrollActive set until the
                                                    // anchored measure has occurred.  It may
                                                    // need to remeasure, which should count
                                                    // as part of the scroll operation
                                                    DispatcherOperation clearIsScrollActiveOperation = ClearIsScrollActiveOperationField.GetValue(this);
                                                    if (clearIsScrollActiveOperation != null)
                                                    {
                                                        clearIsScrollActiveOperation.Abort();
                                                    }
                                                    clearIsScrollActiveOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                                        (Action)ClearIsScrollActive);

                                                    ClearIsScrollActiveOperationField.SetValue(this, clearIsScrollActiveOperation);
                                                }
                                            }
                                        }
                                    };
                                measureCachesOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                                                                measureCachesAction);
                                MeasureCachesOperationField.SetValue(this, measureCachesOperation);
                            }
                        }
                    }
                    else if (IsScrollActive)
                    {
                        DispatcherOperation clearIsScrollActiveOperation = ClearIsScrollActiveOperationField.GetValue(this);
                        if (clearIsScrollActiveOperation == null)
                        {
                            clearIsScrollActiveOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                (Action)ClearIsScrollActive);

                            ClearIsScrollActiveOperationField.SetValue(this, clearIsScrollActiveOperation);
                        }
                    }

                    NormalizeCacheLength(isHorizontal, viewport, ref cacheSize, ref cacheUnit);
                }
                else
                {
                    cacheSize = new VirtualizationCacheLength(
                        Double.PositiveInfinity,
                        IsViewportEmpty(isHorizontal, viewport) ?
                        0.0 :
                        Double.PositiveInfinity);
                    cacheUnit = VirtualizationCacheLengthUnit.Pixel;

                    ClearAsyncOperations();
                }
            }
            else if (virtualizationInfoProvider != null)
            {
                //
                // Adjust the viewport offset for a non scrolling panel to account for the HeaderSize
                // when virtualizing.
                //
                HierarchicalVirtualizationConstraints virtualizationConstraints = virtualizationInfoProvider.Constraints;
                viewport = virtualizationConstraints.Viewport;
                cacheSize = virtualizationConstraints.CacheLength;
                cacheUnit = virtualizationConstraints.CacheLengthUnit;
                MeasureCaches = virtualizationInfoProvider.InBackgroundLayout;

                if (isVSP45Compat)
                {
                    AdjustNonScrollingViewportForHeader(virtualizationInfoProvider, ref viewport, ref cacheSize, ref cacheUnit);
                }
                else
                {
                    AdjustNonScrollingViewportForInset(isHorizontal, parentItem, parentItemStorageProvider, virtualizationInfoProvider, ref viewport, ref cacheSize, ref cacheUnit);

                    // The viewport position may be expressed in an old coordinate system
                    // relying on an old average container size.  Using that position would
                    // produce bad results;  for example the first step in Measure computes
                    // the first item that intersects the viewport - it uses the latest
                    // average container size, and hence would choose the wrong item
                    // (from user's point of view, the panel scrolls to a random place).
                    //      To work around this, ComputeEffectiveOffset stores a list
                    // of substitute offsets when the ave container size changes;
                    // this instructs this method to replace an old offset with a new
                    // one (appearing last) that's the equivalent in the current coordinate
                    // system.
                    //      This replacement stays in effect until the parent panel gives us
                    // an offset from a more recent coordinate change, after which older
                    // offsets won't appear again.   Or an offset that's not on the
                    // list at all, which means a new scroll motion has started.
                    DependencyObject container = virtualizationInfoProvider as DependencyObject;
                    List<Double> offsetList = EffectiveOffsetInformationField.GetValue(container);
                    if (offsetList != null)
                    {
                        if (ScrollTracer.IsEnabled && ScrollTracer.IsTracing(this))
                        {
                            object[] args = new object[offsetList.Count + 1];
                            args[0] = viewport.Location;
                            for (int i=0; i<offsetList.Count; ++i)
                            {
                                args[i+1] = offsetList[i];
                            }
                            ScrollTracer.Trace(this, ScrollTraceOp.UseSubstOffset,
                                args);
                        }

                        // find the given offset on the list
                        double offset = isHorizontal ? viewport.X : viewport.Y;
                        int index = offsetList.IndexOf(offset);

                        // if it appears, susbstitue the last offset
                        if (index >= 0)
                        {
                            if (isHorizontal)
                            {
                                viewport.X = offsetList[offsetList.Count-1];
                            }
                            else
                            {
                                viewport.Y = offsetList[offsetList.Count-1];
                            }

                            // and remove offsets before the matching one -
                            // they'll never be needed again
                            offsetList.RemoveRange(0, index);
                        }

                        // if the list is no longer needed, discard it
                        if (index < 0 || offsetList.Count <= 1)
                        {
                            EffectiveOffsetInformationField.ClearValue(container);
                        }
                    }
                }
            }
            else
            {
                viewport = new Rect(0, 0, constraint.Width, constraint.Height);

                if (isHorizontal)
                {
                    viewport.Width = Double.PositiveInfinity;
                }
                else
                {
                    viewport.Height = Double.PositiveInfinity;
                }
            }

            // Adjust extendedViewport

            extendedViewport = _extendedViewport;

            if (isHorizontal)
            {
                extendedViewport.X += viewport.X - _viewport.X;
            }
            else
            {
                extendedViewport.Y += viewport.Y - _viewport.Y;
            }
        }
Example #16
0
        /// <summary>
        /// Returns the size of the child in pixel and logical units and also identifies the part of the child visible in the viewport.
        /// </summary>
        private void GetSizesForChild(
            bool isHorizontal,
            bool isChildHorizontal,
            bool isBeforeFirstItem,
            bool isAfterLastItem,
            IHierarchicalVirtualizationAndScrollInfo virtualizingChild,
            Size childDesiredSize,
            Rect childViewport,
            VirtualizationCacheLength childCacheSize,
            VirtualizationCacheLengthUnit childCacheUnit,
            out Size childPixelSize,
            out Size childPixelSizeInViewport,
            out Size childPixelSizeInCacheBeforeViewport,
            out Size childPixelSizeInCacheAfterViewport,
            out Size childLogicalSize,
            out Size childLogicalSizeInViewport,
            out Size childLogicalSizeInCacheBeforeViewport,
            out Size childLogicalSizeInCacheAfterViewport)
        {
            childPixelSize = new Size();
            childPixelSizeInViewport = new Size();
            childPixelSizeInCacheBeforeViewport = new Size();
            childPixelSizeInCacheAfterViewport = new Size();

            childLogicalSize = new Size();
            childLogicalSizeInViewport = new Size();
            childLogicalSizeInCacheBeforeViewport = new Size();
            childLogicalSizeInCacheAfterViewport = new Size();

            if (virtualizingChild != null)
            {
                RelativeHeaderPosition headerPosition = RelativeHeaderPosition.Top; // virtualizingChild.RelativeHeaderPosition;
                HierarchicalVirtualizationHeaderDesiredSizes headerDesiredSizes = virtualizingChild.HeaderDesiredSizes;
                HierarchicalVirtualizationItemDesiredSizes itemDesiredSizes = virtualizingChild.ItemDesiredSizes;

                Size pixelHeaderSize = headerDesiredSizes.PixelSize;
                Size logicalHeaderSize = headerDesiredSizes.LogicalSize;

                childPixelSize = childDesiredSize;

                if (headerPosition == RelativeHeaderPosition.Top || headerPosition == RelativeHeaderPosition.Bottom)
                {
                    childLogicalSize.Height = itemDesiredSizes.LogicalSize.Height + logicalHeaderSize.Height;
                    childLogicalSize.Width = Math.Max(itemDesiredSizes.LogicalSize.Width, logicalHeaderSize.Width);
                }
                else // if (headerPosition == RelativeHeaderPosition.Left || headerPosition == RelativeHeaderPosition.Right)
                {
                    childLogicalSize.Width = itemDesiredSizes.LogicalSize.Width + logicalHeaderSize.Width;
                    childLogicalSize.Height = Math.Max(itemDesiredSizes.LogicalSize.Height, logicalHeaderSize.Height);
                }

                if (IsPixelBased &&
                    ((isHorizontal && DoubleUtil.AreClose(itemDesiredSizes.PixelSize.Width, itemDesiredSizes.PixelSizeInViewport.Width)) ||
                    (!isHorizontal && DoubleUtil.AreClose(itemDesiredSizes.PixelSize.Height, itemDesiredSizes.PixelSizeInViewport.Height))))
                {
                    Rect childItemsViewport = childViewport;

                    if (headerPosition == RelativeHeaderPosition.Top || headerPosition == RelativeHeaderPosition.Left)
                    {
                        VirtualizationCacheLength childItemsCacheSize = childCacheSize;
                        VirtualizationCacheLengthUnit childItemsCacheUnit = childCacheUnit;

                        AdjustNonScrollingViewportForHeader(virtualizingChild, ref childItemsViewport, ref childItemsCacheSize, ref childItemsCacheUnit);
                    }

                    GetSizesForChildIntersectingTheViewport(
                        isHorizontal,
                        isChildHorizontal,
                        itemDesiredSizes.PixelSizeInViewport,
                        itemDesiredSizes.LogicalSizeInViewport,
                        childItemsViewport,
                        ref childPixelSizeInViewport,
                        ref childLogicalSizeInViewport,
                        ref childPixelSizeInCacheBeforeViewport,
                        ref childLogicalSizeInCacheBeforeViewport,
                        ref childPixelSizeInCacheAfterViewport,
                        ref childLogicalSizeInCacheAfterViewport);
                }
                else
                {
                    StackSizes(isHorizontal, ref childPixelSizeInViewport, itemDesiredSizes.PixelSizeInViewport);
                    StackSizes(isHorizontal, ref childLogicalSizeInViewport, itemDesiredSizes.LogicalSizeInViewport);
                }

                if (isChildHorizontal == isHorizontal)
                {
                    StackSizes(isHorizontal, ref childPixelSizeInCacheBeforeViewport, itemDesiredSizes.PixelSizeBeforeViewport);
                    StackSizes(isHorizontal, ref childLogicalSizeInCacheBeforeViewport, itemDesiredSizes.LogicalSizeBeforeViewport);
                    StackSizes(isHorizontal, ref childPixelSizeInCacheAfterViewport, itemDesiredSizes.PixelSizeAfterViewport);
                    StackSizes(isHorizontal, ref childLogicalSizeInCacheAfterViewport, itemDesiredSizes.LogicalSizeAfterViewport);
                }

                Rect childHeaderViewport = childViewport;
                Size childHeaderPixelSizeInViewport = new Size();
                Size childHeaderLogicalSizeInViewport = new Size();
                Size childHeaderPixelSizeInCacheBeforeViewport = new Size();
                Size childHeaderLogicalSizeInCacheBeforeViewport = new Size();
                Size childHeaderPixelSizeInCacheAfterViewport = new Size();
                Size childHeaderLogicalSizeInCacheAfterViewport = new Size();
                bool isChildHeaderHorizontal = (headerPosition == RelativeHeaderPosition.Left || headerPosition == RelativeHeaderPosition.Right);

                if (headerPosition == RelativeHeaderPosition.Bottom || headerPosition == RelativeHeaderPosition.Right)
                {
                    VirtualizationCacheLength childHeaderCacheSize = childCacheSize;
                    VirtualizationCacheLengthUnit childHeaderCacheUnit = childCacheUnit;

                    AdjustNonScrollingViewportForItems(virtualizingChild, ref childHeaderViewport, ref childHeaderCacheSize, ref childHeaderCacheUnit);
                }

                if (isBeforeFirstItem)
                {
                    childHeaderPixelSizeInCacheBeforeViewport = pixelHeaderSize;
                    childHeaderLogicalSizeInCacheBeforeViewport = logicalHeaderSize;
                }
                else if (isAfterLastItem)
                {
                    childHeaderPixelSizeInCacheAfterViewport = pixelHeaderSize;
                    childHeaderLogicalSizeInCacheAfterViewport = logicalHeaderSize;
                }
                else
                {
                    GetSizesForChildIntersectingTheViewport(
                        isHorizontal,
                        isChildHorizontal,
                        pixelHeaderSize,
                        logicalHeaderSize,
                        childHeaderViewport,
                        ref childHeaderPixelSizeInViewport,
                        ref childHeaderLogicalSizeInViewport,
                        ref childHeaderPixelSizeInCacheBeforeViewport,
                        ref childHeaderLogicalSizeInCacheBeforeViewport,
                        ref childHeaderPixelSizeInCacheAfterViewport,
                        ref childHeaderLogicalSizeInCacheAfterViewport);
                }

                StackSizes(isChildHeaderHorizontal, ref childPixelSizeInViewport, childHeaderPixelSizeInViewport);
                StackSizes(isChildHeaderHorizontal, ref childLogicalSizeInViewport, childHeaderLogicalSizeInViewport);
                StackSizes(isChildHeaderHorizontal, ref childPixelSizeInCacheBeforeViewport, childHeaderPixelSizeInCacheBeforeViewport);
                StackSizes(isChildHeaderHorizontal, ref childLogicalSizeInCacheBeforeViewport, childHeaderLogicalSizeInCacheBeforeViewport);
                StackSizes(isChildHeaderHorizontal, ref childPixelSizeInCacheAfterViewport, childHeaderPixelSizeInCacheAfterViewport);
                StackSizes(isChildHeaderHorizontal, ref childLogicalSizeInCacheAfterViewport, childHeaderLogicalSizeInCacheAfterViewport);
            }
            else
            {
                childPixelSize = childDesiredSize;
                childLogicalSize = new Size(DoubleUtil.GreaterThan(childPixelSize.Width, 0) ? 1 : 0,
                                            DoubleUtil.GreaterThan(childPixelSize.Height, 0) ? 1 : 0);

                if (isBeforeFirstItem)
                {
                    childPixelSizeInCacheBeforeViewport = childDesiredSize;
                    childLogicalSizeInCacheBeforeViewport = new Size(DoubleUtil.GreaterThan(childPixelSizeInCacheBeforeViewport.Width, 0) ? 1 : 0,
                                                                     DoubleUtil.GreaterThan(childPixelSizeInCacheBeforeViewport.Height, 0) ? 1 : 0);
                }
                else if (isAfterLastItem)
                {
                    childPixelSizeInCacheAfterViewport = childDesiredSize;
                    childLogicalSizeInCacheAfterViewport = new Size(DoubleUtil.GreaterThan(childPixelSizeInCacheAfterViewport.Width, 0) ? 1 : 0,
                                                                    DoubleUtil.GreaterThan(childPixelSizeInCacheAfterViewport.Height, 0) ? 1 : 0);
                }
                else
                {
                    GetSizesForChildIntersectingTheViewport(
                        isHorizontal,
                        isHorizontal,
                        childPixelSize,
                        childLogicalSize,
                        childViewport,
                        ref childPixelSizeInViewport,
                        ref childLogicalSizeInViewport,
                        ref childPixelSizeInCacheBeforeViewport,
                        ref childLogicalSizeInCacheBeforeViewport,
                        ref childPixelSizeInCacheAfterViewport,
                        ref childLogicalSizeInCacheAfterViewport);
                }
            }
        }
Example #17
0
        /// <summary>
        /// Initializes the owner and interfaces for the virtualization services it supports.
        /// </summary>
        private void GetOwners(
            bool shouldSetVirtualizationState,
            bool isHorizontal,
            out ItemsControl itemsControl,
            out GroupItem groupItem,
            out IContainItemStorage itemStorageProvider,
            out IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            out object parentItem,
            out bool mustDisableVirtualization)
        {
            groupItem = null;
            parentItem = null;

            bool isScrolling = IsScrolling;

            mustDisableVirtualization = isScrolling ? MustDisableVirtualization : false;

            DependencyObject itemsOwner = ItemsControl.GetItemsOwnerInternal(this, out itemsControl);
            if (itemsOwner != itemsControl)
            {
                groupItem = itemsOwner as GroupItem;
                parentItem = itemsControl.ItemContainerGenerator.ItemFromContainer(groupItem);
            }
            else if (!isScrolling)
            {
                ItemsControl parentItemsControl = ItemsControl.GetItemsOwnerInternal(VisualTreeHelper.GetParent(itemsControl)) as ItemsControl;
                if (parentItemsControl != null)
                {
                    parentItem = parentItemsControl.ItemContainerGenerator.ItemFromContainer(itemsControl);
                }
                else
                {
                    parentItem = this;
                }
            }
            else
            {
                parentItem = this;
            }

            itemStorageProvider = itemsOwner as IContainItemStorage;
            virtualizationInfoProvider = null;

            if (groupItem != null)
            {
                virtualizationInfoProvider = GetVirtualizingProvider(groupItem);
                mustDisableVirtualization = virtualizationInfoProvider != null ? virtualizationInfoProvider.MustDisableVirtualization : false;
            }
            else if (!isScrolling)
            {
                virtualizationInfoProvider = GetVirtualizingProvider(itemsControl);
                mustDisableVirtualization = virtualizationInfoProvider != null ? virtualizationInfoProvider.MustDisableVirtualization : false;
            }

            if (shouldSetVirtualizationState)
            {
                //
                // Synchronize properties such as IsVirtualizing, IsRecycling & IsPixelBased
                //
                SetVirtualizationState(itemStorageProvider, itemsControl, mustDisableVirtualization);
            }
        }
        /// <summary>
        /// Initializes the viewport for this panel.
        /// </summary>
        private void InitializeViewport(
            object parentItem,
            IContainItemStorage parentItemStorageProvider,
            IHierarchicalVirtualizationAndScrollInfo virtualizationInfoProvider,
            bool isHorizontal,
            Size constraint,
            ref Rect viewport,
            ref VirtualizationCacheLength cacheSize,
            ref VirtualizationCacheLengthUnit cacheUnit,
            out Rect extendedViewport)
        {

            Size extent = new Size();
            bool isVSP45Compat = IsVSP45Compat;

            if (IsScrolling)
            {
                //
                // We're the top level scrolling panel. Fetch the offset from the _scrollData.
                //

                Size size;
                double offsetX, offsetY;
                Size viewportSize;

                size = constraint;
                offsetX = _scrollData._offset.X;
                offsetY = _scrollData._offset.Y;
                extent = _scrollData._extent;
                viewportSize = _scrollData._viewport;

                if (!IsScrollActive || IgnoreMaxDesiredSize)
                {
                    _scrollData._maxDesiredSize = new Size();
                }

                if (IsPixelBased)
                {
                    viewport = new Rect(offsetX, offsetY, size.Width, size.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                }
                else
                {
                    viewport = new Rect(offsetX, offsetY, viewportSize.Width, viewportSize.Height);
                    CoerceScrollingViewportOffset(ref viewport, extent, isHorizontal);
                    viewport.Size = size;
                }

                if (IsVirtualizing)
                {
                    cacheSize = VirtualizingStackPanel.GetCacheLength(this);
                    cacheUnit = VirtualizingStackPanel.GetCacheLengthUnit(this);

                    if (DoubleUtil.GreaterThan(cacheSize.CacheBeforeViewport, 0) ||
                        DoubleUtil.GreaterThan(cacheSize.CacheAfterViewport, 0))
                    {
                        if (!MeasureCaches)
                        {
                            WasLastMeasurePassAnchored = (_firstContainerInViewport != null) || (_bringIntoViewLeafContainer != null);

                            DispatcherOperation measureCachesOperation = MeasureCachesOperationField.GetValue(this);
                            if (measureCachesOperation == null)
                            {
                                Action measureCachesAction = null;
                                int retryCount = 3;
                                measureCachesAction = (Action)delegate()
                                    {
                                        Debug.Assert(retryCount >=0, "retry MeasureCaches too often");
                                        bool isLayoutDirty = (0 < retryCount--) && (MeasureDirty || ArrangeDirty);
                                        try
                                        {
                                            if (isVSP45Compat || !isLayoutDirty)
                                            {
                                                MeasureCachesOperationField.ClearValue(this);

                                                MeasureCaches = true;

                                                if (WasLastMeasurePassAnchored)
                                                {
                                                    SetAnchorInformation(isHorizontal);
                                                }

                                                InvalidateMeasure();
                                                UpdateLayout();
                                            }
                                        }
                                        finally
                                        {
                                            // check whether UpdateLayout finished the job
                                            isLayoutDirty = isLayoutDirty ||
                                                    ((0 < retryCount) && (MeasureDirty || ArrangeDirty));
                                            if (!isVSP45Compat && isLayoutDirty)
                                            {
                                                // try the measure-cache pass again later.
                                                // Note that we only do this when:
                                                // 1. this VSP's layout is dirty, either because
                                                //    a. it was dirty to begin with so we
                                                //       skipped UpdateLayout, or
                                                //    b. UpdateLayout ran, but left this VSP's
                                                //       layout dirty.
                                                // 2. we haven't run out of retries
                                                // 3. we're not in 4.5-compat mode
                                                //
                                                // (1) can happen if layout times out and moves to
                                                //     background.
                                                // (2) protects against loops when an app calls
                                                //     VSP.Measure directly, outside of the normal
                                                //     layout system (real appps don't do this,
                                                //     but test code does - it happens in the DrtXaml test).
                                                // (3) preserves compat with 4.5RTM, where the
                                                //     "move to background" situation led to an
                                                //     infinite loop.
                                                MeasureCachesOperationField.SetValue(this,
                                                    Dispatcher.BeginInvoke(DispatcherPriority.Background, measureCachesAction));
                                            }

                                            MeasureCaches = false;

                                            // If there is a pending anchor operation that got registered in
                                            // the current pass, or if layout didn't finish, we don't want to
                                            // clear the IsScrollActive flag.
                                            // We should allow that measure pass to also settle and then clear
                                            // the flag.

                                            DispatcherOperation anchoredInvalidateMeasureOperation = AnchoredInvalidateMeasureOperationField.GetValue(this);
                                            if (anchoredInvalidateMeasureOperation == null && (isVSP45Compat || !isLayoutDirty))
                                            {
                                                if (isVSP45Compat)
                                                {
                                                    IsScrollActive = false;
                                                }
                                                else if (IsScrollActive)
                                                {
                                                    // keep IsScrollActive set until the
                                                    // anchored measure has occurred.  It may
                                                    // need to remeasure, which should count
                                                    // as part of the scroll operation
                                                    DispatcherOperation clearIsScrollActiveOperation = ClearIsScrollActiveOperationField.GetValue(this);
                                                    if (clearIsScrollActiveOperation != null)
                                                    {
                                                        clearIsScrollActiveOperation.Abort();
                                                    }
                                                    clearIsScrollActiveOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                                        (Action)ClearIsScrollActive);

                                                    ClearIsScrollActiveOperationField.SetValue(this, clearIsScrollActiveOperation);
                                                }
                                            }
                                        }
                                    };
                                measureCachesOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                                                                measureCachesAction);
                                MeasureCachesOperationField.SetValue(this, measureCachesOperation);
                            }
                        }
                    }
                    else if (IsScrollActive)
                    {
                        DispatcherOperation clearIsScrollActiveOperation = ClearIsScrollActiveOperationField.GetValue(this);
                        if (clearIsScrollActiveOperation == null)
                        {
                            clearIsScrollActiveOperation = Dispatcher.BeginInvoke(DispatcherPriority.Background,
                                (Action)ClearIsScrollActive);

                            ClearIsScrollActiveOperationField.SetValue(this, clearIsScrollActiveOperation);
                        }
                    }

                    NormalizeCacheLength(isHorizontal, viewport, ref cacheSize, ref cacheUnit);
                }
                else
                {
                    cacheSize = new VirtualizationCacheLength(
                        Double.PositiveInfinity,
                        IsViewportEmpty(isHorizontal, viewport) ?
                        0.0 :
                        Double.PositiveInfinity);
                    cacheUnit = VirtualizationCacheLengthUnit.Pixel;

                    ClearAsyncOperations();
                }
            }
            else if (virtualizationInfoProvider != null)
            {
                //
                // Adjust the viewport offset for a non scrolling panel to account for the HeaderSize
                // when virtualizing.
                //
                HierarchicalVirtualizationConstraints virtualizationConstraints = virtualizationInfoProvider.Constraints;
                viewport = virtualizationConstraints.Viewport;
                cacheSize = virtualizationConstraints.CacheLength;
                cacheUnit = virtualizationConstraints.CacheLengthUnit;
                MeasureCaches = virtualizationInfoProvider.InBackgroundLayout;

                if (isVSP45Compat)
                {
                    AdjustNonScrollingViewportForHeader(virtualizationInfoProvider, ref viewport, ref cacheSize, ref cacheUnit);
                }
                else
                {
                    AdjustNonScrollingViewportForInset(isHorizontal, parentItem, parentItemStorageProvider, virtualizationInfoProvider, ref viewport, ref cacheSize, ref cacheUnit);
                }
            }
            else
            {
                viewport = new Rect(0, 0, constraint.Width, constraint.Height);

                if (isHorizontal)
                {
                    viewport.Width = Double.PositiveInfinity;
                }
                else
                {
                    viewport.Height = Double.PositiveInfinity;
                }
            }

            // Adjust extendedViewport

            extendedViewport = _extendedViewport;

            if (isHorizontal)
            {
                extendedViewport.X += viewport.X - _viewport.X;
            }
            else
            {
                extendedViewport.Y += viewport.Y - _viewport.Y;
            }
        }