Exemplo n.º 1
0
        private void SetItemsHostInsetForChild(int index, UIElement child, IContainItemStorage itemStorageProvider, bool isHorizontal)
        {
            Debug.Assert(!IsVSP45Compat, "SetItemsHostInset should not be called in VSP45-compat mode");

            // this only applies to a hierarchical element with a visible ItemsHost
            bool isChildHorizontal = isHorizontal;
            IHierarchicalVirtualizationAndScrollInfo virtualizingChild = GetVirtualizingChild(child, ref isChildHorizontal);
            Panel itemsHost = (virtualizingChild == null) ? null : virtualizingChild.ItemsHost;
            if (itemsHost == null || !itemsHost.IsVisible)
                return;

            // get the transformation from child coords to itemsHost coords
            GeneralTransform transform = child.TransformToDescendant(itemsHost);
            if (transform == null)
                return;     // when transform is undefined, ItemsHost is effectively invisible

            // build a rect (in child coords) describing the child's extended frame
            FrameworkElement fe = virtualizingChild as FrameworkElement;
            Thickness margin = (fe == null) ? new Thickness() : fe.Margin;
            Rect childRect = new Rect(new Point(), child.DesiredSize);
            childRect.Offset(-margin.Left, -margin.Top);

            // transform to itemsHost coords
            Rect itemsRect = transform.TransformBounds(childRect);

            // compute the desired inset, avoiding catastrophic cancellation errors
            Size itemsSize = itemsHost.DesiredSize;
            double left = DoubleUtil.AreClose(0, itemsRect.Left) ? 0 : -itemsRect.Left;
            double top = DoubleUtil.AreClose(0, itemsRect.Top) ? 0 : -itemsRect.Top;
            double right = DoubleUtil.AreClose(itemsSize.Width, itemsRect.Right) ? 0 : itemsRect.Right-itemsSize.Width;
            double bottom = DoubleUtil.AreClose(itemsSize.Height, itemsRect.Bottom) ? 0 : itemsRect.Bottom-itemsSize.Height;
            Thickness inset = new Thickness(left, top, right, bottom);


            // get the item to use as the key into items storage
            object item = GetItemFromContainer(child);
            if (item == DependencyProperty.UnsetValue)
            {
                Debug.Assert(false, "SetInset should only be called for a container");
                return;
            }

            // see whether inset is changing
            object box = itemStorageProvider.ReadItemValue(item, ItemsHostInsetProperty);
            bool changed = (box == null);
            bool remeasure = changed;
            if (!changed)
            {
                Thickness oldInset = (Thickness)box;
                changed = !(    DoubleUtil.AreClose(oldInset.Left, inset.Left) &&
                                DoubleUtil.AreClose(oldInset.Top, inset.Top ) &&
                                DoubleUtil.AreClose(oldInset.Right, inset.Right) &&
                                DoubleUtil.AreClose(oldInset.Bottom, inset.Bottom) );

                // only changes along the scrolling axis require a remeasure.
                // use a less stringent "AreClose" test;  experiments show that the
                // trailing inset can change due to roundoff error by an amount
                // that is larger than the tolerance in DoubleUtil, but not large
                // enough to warrant an expensive remeasure.
                remeasure = changed &&
                    (   (isHorizontal  && !(AreInsetsClose(oldInset.Left, inset.Left) &&
                                            AreInsetsClose(oldInset.Right, inset.Right)))
                     || (!isHorizontal && !(AreInsetsClose(oldInset.Top, inset.Top) &&
                                            AreInsetsClose(oldInset.Bottom, inset.Bottom))) );
            }

            if (changed)
            {
                // store the new inset
                itemStorageProvider.StoreItemValue(item, ItemsHostInsetProperty, inset);
                child.SetValue(ItemsHostInsetProperty, inset);
            }

            if (remeasure)
            {
                // re-measure the scrolling panel
                ItemsControl scrollingItemsControl = GetScrollingItemsControl(child);
                Panel scrollingPanel = (scrollingItemsControl == null) ? null : scrollingItemsControl.ItemsHost;
                if (scrollingPanel != null)
                {
                    VirtualizingStackPanel vsp = scrollingPanel as VirtualizingStackPanel;
                    if (vsp != null)
                    {
                        vsp.AnchoredInvalidateMeasure();
                    }
                    else
                    {
                        scrollingPanel.InvalidateMeasure();
                    }
                }
            }
        }