Exemple #1
0
 public bool IsWithin(VerticalArea area)
 {
     return
         ((area.Top >= Top && area.Top <= Bottom)
          ||
          (area.Bottom >= Top && area.Bottom <= Bottom)
          ||
          (area.Top <= Top && area.Bottom >= Bottom));
 }
 public bool IsWithin(VerticalArea area)
 {
     return 
     (area.Top >= Top && area.Top <= Bottom)
     ||
     (area.Bottom >= Top && area.Bottom <= Bottom)
     ||
     (area.Top<= Top && area.Bottom >= Bottom);
 }
        public void IsWithin()
        {
            var va = new VerticalArea { Top = 100, Bottom = 200 };
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 100, Bottom = 200 }));
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 110, Bottom = 200 }));
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 100, Bottom = 150 }));
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 150, Bottom = 250 }));
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 0, Bottom = 150 }));
            Assert.IsTrue(va.IsWithin(new VerticalArea { Top = 0, Bottom = 300 }));


            Assert.IsFalse(va.IsWithin(new VerticalArea { Top = 0, Bottom = 10 }));
            Assert.IsFalse(va.IsWithin(new VerticalArea { Top = 250, Bottom = 300 }));
        }
        /// <summary>
        /// Measure the children
        /// </summary>
        /// <param name="availableSize">Size available</param>
        /// <returns>Size desired</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            if (ScrollOwner != null)
            {
                if (ScrollOwner.ScrollableWidth < HorizontalOffset) SetHorizontalOffset(ScrollOwner.ScrollableWidth);
                if (ScrollOwner.ScrollableHeight < VerticalOffset) SetVerticalOffset(ScrollOwner.ScrollableHeight);
            }

            // We need to access InternalChildren before the generator to work around a bug
            UIElementCollection children = InternalChildren;
            IItemContainerGenerator generator = ItemContainerGenerator;
            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
            TreeViewExItem treeViewItem = itemsControl as TreeViewExItem;
            TreeViewEx treeView = itemsControl as TreeViewEx ?? treeViewItem.ParentTreeView;
            Debug(treeViewItem, "Measuring");
            double maxWidth = 0;
            double currentYinItemSystem = 0;

            if (treeView.IsVirtualizing)
            {
                // never forget: virtualization of a tree is an approximation. there are some use cases which theoretically work and others
                // we try to get it working by estimations. See GetCachedOrEstimatedHeight for more infos.

                int itemCount = itemsControl.Items.Count;
                int firstVisibleItemIndex = 0;
                int lastVisibleItemIndex = itemCount;

                double itemTop;
                if (treeViewItem != null)
                {
                    itemTop = treeViewItem.itemTopInTreeSystem + GetHeightOfHeader(itemsControl);
                }
                else
                {
                    // get the area where items have to be visualized. This is from top to bottom of the visible space in tree system. 
                    // We add a little of offset. It seems like it improves estimation of heights.
                    double predictionOffset = 50;
                    double top = VerticalOffset - predictionOffset;
                    if (top < 0) top = 0;
                    treeView.realizationSpace.Top = top;
                    treeView.realizationSpace.Bottom = VerticalOffset + availableSize.Height + predictionOffset;

                    itemTop = GetHeightOfHeader(itemsControl);
                }

                int itemGeneratorIndex = 0;
                bool isPreviousItemVisible = false;
                IDisposable generatorRun = null;
                currentYinItemSystem = 0;
                int childHierarchyLevel = 0;
                if(treeViewItem != null) childHierarchyLevel = treeViewItem.hierachyLevel + 1;
                try
                {
                    // iterate child items
                    for (int i = 0; i < itemCount; i++)
                    {
                        double estimatedHeight = GetCachedOrEstimatedHeight(treeView, childHierarchyLevel);
                        VerticalArea childSpace = new VerticalArea();
                        childSpace.Top = itemTop + currentYinItemSystem;
                        childSpace.Bottom = childSpace.Top + estimatedHeight;

                        // check if item is possibly visible or could become visible if someone changes expanding of siblings
                        bool isVisibleItem = treeView.realizationSpace.IsWithin(childSpace);

                        if (isVisibleItem)
                        {
                            // we have found a visible item, lets check if its the first visible item.
                            if (!isPreviousItemVisible)
                            {
                                // we found a visible item, lets initialize the visible item section of the loop
                                isPreviousItemVisible = true;
                                firstVisibleItemIndex = i;
                                GeneratorPosition startPos = generator.GeneratorPositionFromIndex(i);
                                itemGeneratorIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1;
                                generatorRun = generator.StartAt(startPos, GeneratorDirection.Forward, true);
                            }
                            else
                            {
                                itemGeneratorIndex++;
                            }

                            // Get or create the child
                            bool newlyRealized;
                            TreeViewExItem child = generator.GenerateNext(out newlyRealized) as TreeViewExItem;
                            Debug(treeViewItem, "Found visible child: " + child.DataContext);

                            if (newlyRealized)
                            {
                                // Figure out if we need to insert the child at the end or somewhere in the middle
                                AddOrInsertItemToInternalChildren(itemGeneratorIndex, child);
                                child.ParentTreeView = treeView;
                                generator.PrepareItemContainer(child);
                            }
                            else
                            {
                                // The child has already been created, let's be sure it's in the right spot
                                if (child != children[itemGeneratorIndex]) throw new InvalidOperationException("Wrong child was generated");
                            }

                            if (treeViewItem != null)
                            {
                                child.itemTopInTreeSystem = currentYinItemSystem + itemTop;
                                child.hierachyLevel = treeViewItem.hierachyLevel + 1;
                            }
                            else
                            {
                                child.itemTopInTreeSystem = currentYinItemSystem;
                                child.hierachyLevel = 1;
                            }

                            InvalidateMeasure(child);
                            child.Measure(new Size(double.MaxValue, double.MaxValue));

                            // add real height to cache
                            double heightOfChild = child.DesiredSize.Height;
                            RegisterHeight(treeView, childHierarchyLevel, heightOfChild);
                            currentYinItemSystem += child.DesiredSize.Height;
                            // save the maximum needed width
                            maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
                        }
                        else
                        {
                            //Debug(treeViewItem, "Found invisible child: " + i);
                            if (isPreviousItemVisible)
                            {
                                // set last visible index. this is important, to cleanup not anymore used items
                                lastVisibleItemIndex = i;
                                isPreviousItemVisible = false;
                            }

                            // dispose generator run. if we do it after the whole loop, we run in multithreading issues
                            if (generatorRun != null)
                            {
                                generatorRun.Dispose();
                                generatorRun = null;
                            }

                            currentYinItemSystem += GetCachedOrEstimatedHeight(treeView, childHierarchyLevel);
                        }
                        //Debug(treeViewItem, "Current y for " + i + ": " + currentYinItemSystem);
                    }
                }
                finally
                {
                    //just for safety
                    if (generatorRun != null)
                    {
                        generatorRun.Dispose();
                        generatorRun = null;
                    }
                }

                //Debug("Cleaning all items but " + firstVisibleItemIndex + " to " + lastVisibleItemIndex + " for element " + itemsControl.DataContext);
                CleanUpItems(firstVisibleItemIndex, lastVisibleItemIndex);
            }
            else
            {
                //Debug("Virtualization is OFF.");
                GeneratorPosition startPos = generator.GeneratorPositionFromIndex(0);
                using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
                {
                    for (int i = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1; i < itemsControl.Items.Count; i++)
                    {
                        // Get or create the child
                        bool newlyRealized;
                        TreeViewExItem child = generator.GenerateNext(out newlyRealized) as TreeViewExItem;
                        if (newlyRealized)
                        {
                            // Figure out if we need to insert the child at the end or somewhere in the middle
                            AddOrInsertItemToInternalChildren(i, child);
                            child.ParentTreeView = treeView ?? treeViewItem.ParentTreeView;
                            generator.PrepareItemContainer(child);
                        }

                        child.Measure(new Size(double.MaxValue, double.MaxValue));
                        // now get the real height
                        double height = child.DesiredSize.Height;
                        // add real height to current position
                        currentYinItemSystem += height;
                        // save the maximum needed width
                        maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
                    }
                }
            }

            if (double.IsPositiveInfinity(maxWidth) || double.IsPositiveInfinity(currentYinItemSystem))
            {
                throw new InvalidOperationException("???");
            }

            Extent = new Size(maxWidth, currentYinItemSystem);
            Viewport = availableSize;
            Debug(treeViewItem, "Desired height: " + Extent.Height);
            return Extent;
        }
Exemple #5
0
 public bool Overlaps(VerticalArea area)
 {
     return Top <= area.Bottom && area.Top <= Bottom;
 }
Exemple #6
0
        /// <summary>
        /// Measure the children
        /// </summary>
        /// <param name="availableSize">Size available</param>
        /// <returns>Size desired</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            if (ScrollOwner != null)
            {
                if (ScrollOwner.ScrollableWidth < HorizontalOffset) SetHorizontalOffset(ScrollOwner.ScrollableWidth);
                if (ScrollOwner.ScrollableHeight < VerticalOffset) SetVerticalOffset(ScrollOwner.ScrollableHeight);
            }

            // We need to access InternalChildren before the generator to work around a bug
            UIElementCollection children = InternalChildren;
            IItemContainerGenerator generator = ItemContainerGenerator;
            ItemsControl itemsControl = ItemsControl.GetItemsOwner(this);
            TreeViewItem treeViewItem = itemsControl as TreeViewItem;
            TreeView treeView = itemsControl as TreeView ?? treeViewItem.ParentTreeView;
            Debug(treeViewItem, "Measuring");
            double maxWidth = 0;
            double currentYinItemSystem = 0;

            if (treeView.IsVirtualizing)
            {
                // never forget: virtualization of a tree is an approximation. there are some use cases which theoretically work and others
                // we try to get it working by estimations. See GetCachedOrEstimatedHeight for more infos.

                int itemCount = itemsControl.Items.Count;
                int firstVisibleItemIndex = 0;
                int lastVisibleItemIndex = itemCount;

                double itemTop;
                if (treeViewItem != null)
                {
                    itemTop = treeViewItem.ItemTopInTreeSystem + GetHeightOfHeader(itemsControl);
                }
                else
                {
                    // get the area where items have to be visualized. This is from top to bottom of the visible space in tree system. 
                    // We add a little of offset. It seems like it improves estimation of heights.
                    double predictionOffset = 50;
                    double top = VerticalOffset - predictionOffset;
                    if (top < 0) top = 0;
                    treeView.RealizationSpace.Top = top;
                    treeView.RealizationSpace.Bottom = VerticalOffset + availableSize.Height + predictionOffset;

                    itemTop = GetHeightOfHeader(itemsControl);
                }

                int itemGeneratorIndex = 0;
                bool isPreviousItemVisible = false;
                IDisposable generatorRun = null;
                currentYinItemSystem = 0;
                int childHierarchyLevel = 0;
                if(treeViewItem != null) childHierarchyLevel = treeViewItem.HierachyLevel + 1;
                try
                {
                    // iterate child items
                    for (int i = 0; i < itemCount; i++)
                    {
                        double estimatedHeight = GetCachedOrEstimatedHeight(treeView, childHierarchyLevel);
                        VerticalArea childSpace = new VerticalArea();
                        childSpace.Top = itemTop + currentYinItemSystem;
                        childSpace.Bottom = childSpace.Top + estimatedHeight;

                        // check if item is possibly visible or could become visible if someone changes expanding of siblings
                        bool isVisibleItem = treeView.RealizationSpace.Overlaps(childSpace);

                        if (isVisibleItem)
                        {
                            // we have found a visible item, lets check if its the first visible item.
                            if (!isPreviousItemVisible)
                            {
                                // we found a visible item, lets initialize the visible item section of the loop
                                isPreviousItemVisible = true;
                                firstVisibleItemIndex = i;
                                GeneratorPosition startPos = generator.GeneratorPositionFromIndex(i);
                                itemGeneratorIndex = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1;
                                generatorRun = generator.StartAt(startPos, GeneratorDirection.Forward, true);
                            }
                            else
                            {
                                itemGeneratorIndex++;
                            }

                            // Get or create the child
                            bool newlyRealized;
                            TreeViewItem child = generator.GenerateNext(out newlyRealized) as TreeViewItem;
                            Debug(treeViewItem, "Found visible child: " + child.DataContext);

                            if (newlyRealized)
                            {
                                // Figure out if we need to insert the child at the end or somewhere in the middle
                                AddOrInsertItemToInternalChildren(itemGeneratorIndex, child);
                                child.ParentTreeView = treeView;
                                generator.PrepareItemContainer(child);
                            }
                            else
                            {
                                // The child has already been created, let's be sure it's in the right spot
                                if (child != children[itemGeneratorIndex]) throw new InvalidOperationException("Wrong child was generated");
                            }

                            if (treeViewItem != null)
                            {
                                child.ItemTopInTreeSystem = currentYinItemSystem + itemTop;
                                child.HierachyLevel = treeViewItem.HierachyLevel + 1;
                            }
                            else
                            {
                                child.ItemTopInTreeSystem = currentYinItemSystem;
                                child.HierachyLevel = 1;
                            }

                            InvalidateMeasure(child);
                            child.Measure(new Size(double.MaxValue, double.MaxValue));

                            // add real height to cache
                            double heightOfChild = child.DesiredSize.Height;
                            RegisterHeight(treeView, childHierarchyLevel, heightOfChild);
                            currentYinItemSystem += child.DesiredSize.Height;
                            // save the maximum needed width
                            maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
                        }
                        else
                        {
                            //Debug(treeViewItem, "Found invisible child: " + i);
                            if (isPreviousItemVisible)
                            {
                                // set last visible index. this is important, to cleanup not anymore used items
                                lastVisibleItemIndex = i;
                                isPreviousItemVisible = false;
                            }

                            // dispose generator run. if we do it after the whole loop, we run in multithreading issues
                            if (generatorRun != null)
                            {
                                generatorRun.Dispose();
                                generatorRun = null;
                            }

                            currentYinItemSystem += GetCachedOrEstimatedHeight(treeView, childHierarchyLevel);
                        }
                        //Debug(treeViewItem, "Current y for " + i + ": " + currentYinItemSystem);
                    }
                }
                finally
                {
                    //just for safety
                    if (generatorRun != null)
                    {
                        generatorRun.Dispose();
                        generatorRun = null;
                    }
                }

                //Debug("Cleaning all items but " + firstVisibleItemIndex + " to " + lastVisibleItemIndex + " for element " + itemsControl.DataContext);
                CleanUpItems(firstVisibleItemIndex, lastVisibleItemIndex);
            }
            else
            {
                //Debug("Virtualization is OFF.");
                GeneratorPosition startPos = generator.GeneratorPositionFromIndex(0);
                using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
                {
                    for (int i = (startPos.Offset == 0) ? startPos.Index : startPos.Index + 1; i < itemsControl.Items.Count; i++)
                    {
                        // Get or create the child
                        bool newlyRealized;
                        TreeViewItem child = generator.GenerateNext(out newlyRealized) as TreeViewItem;
                        if (newlyRealized)
                        {
                            // Figure out if we need to insert the child at the end or somewhere in the middle
                            AddOrInsertItemToInternalChildren(i, child);
                            child.ParentTreeView = treeView ?? treeViewItem.ParentTreeView;
                            generator.PrepareItemContainer(child);
                        }

                        child.Measure(new Size(double.MaxValue, double.MaxValue));
                        // now get the real height
                        double height = child.DesiredSize.Height;
                        // add real height to current position
                        currentYinItemSystem += height;
                        // save the maximum needed width
                        maxWidth = Math.Max(maxWidth, child.DesiredSize.Width);
                    }
                }
            }

            if (double.IsPositiveInfinity(maxWidth) || double.IsPositiveInfinity(currentYinItemSystem))
            {
                throw new InvalidOperationException("???");
            }

            Extent = new Size(maxWidth, currentYinItemSystem);
            Viewport = availableSize;
            Debug(treeViewItem, "Desired height: " + Extent.Height);
            return Extent;
        }