Пример #1
0
        /// <summary>
        /// WPF Measure override for measuring the control
        /// </summary>
        /// <param name="availableSize">Available size will be the viewport size in the scroll viewer</param>
        /// <returns>availableSize</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            //base.MeasureOverride(availableSize);

            // We will be given the visible size in the scroll viewer here.
            CalculateExtent();

            if (availableSize != _viewPortSize)
            {
                SetViewportSize(availableSize);
            }

            foreach (FrameworkElement child in this.InternalChildren)
            {
                IVirtualChild n = child.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    Rect bounds = n.Bounds;
                    child.Measure(bounds.Size);
                }
            }
            if (double.IsInfinity(availableSize.Width))
            {
                return(_extent);
            }
            else
            {
                return(availableSize);
            }
        }
Пример #2
0
        /// <summary>
        /// Check all child nodes to see if any leaked from LazyRemoveNodes and remove their visuals.
        /// </summary>
        /// <param name="quantum">Amount of work we can do here</param>
        /// <returns>The amount of work we did</returns>
        int LazyGarbageCollectNodes(int quantum)
        {
            int count = 0;

            // Now after every update also do a full incremental scan over all the children
            // to make sure we didn't leak any nodes that need to be removed.
            while (count < quantum && _nodeCollectCycle < Children.Count)
            {
                UIElement     e = Children[_nodeCollectCycle++];
                IVirtualChild n = e.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    Rect nrect = n.Bounds;
                    if (!nrect.IntersectsWith(_visible))
                    {
                        e.ClearValue(VirtualChildProperty);

                        n.DisposeVisual();
                        e.UpdateLayout();
                        Children.Remove(e);
                        _removed++;
                    }
                    count++;
                }
                _nodeCollectCycle++;
            }

            if (_nodeCollectCycle < Children.Count)
            {
                _done = false;
            }

            return(count);
        }
Пример #3
0
        /// <summary>
        /// WPF ArrangeOverride for laying out the control
        /// </summary>
        /// <param name="finalSize">The size allocated by parents</param>
        /// <returns>finalSize</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            //base.ArrangeOverride(finalSize);

            CalculateExtent();

            if (finalSize != _viewPortSize)
            {
                SetViewportSize(finalSize);
            }

//            base.Arrange(new Rect(0, 0, Width, Height));
            foreach (FrameworkElement child in this.InternalChildren)
            {
                IVirtualChild n = child.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    Rect bounds = n.Bounds;
                    bounds.X -= _translate.X / _scale.ScaleX;
                    bounds.Y -= _translate.Y / _scale.ScaleY;
                    child.Arrange(bounds);
                }
            }

            if (_index == null)
            {
                StartLazyUpdate();
            }

            return(finalSize);
        }
Пример #4
0
        /// <summary>
        /// Resets the state so there is no Visuals associated with this canvas.
        /// </summary>
        private void RebuildVisuals()
        {
            // need to rebuild the index.
            _index           = null;
            _visualPositions = null;
            _visible         = Rect.Empty;
            _done            = false;

            // var stopWatch = Stopwatch.StartNew();

            foreach (UIElement e in _content.Children)
            {
                IVirtualChild n = e.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    e.ClearValue(VirtualChildProperty);
                    n.DisposeVisual();
                }
            }
            //   耗时 2.5us - 8.0us
            // Console.WriteLine("foreach loop execution time = {0} us\n", stopWatch.Elapsed.TotalSeconds*1000000);

            _content.Children.Clear();
            _content.Children.Add(_backdrop);

            InvalidateArrange();
            StartLazyUpdate();
        }
Пример #5
0
 /// <summary>
 /// Resets the state so there is no Visuals associated with this canvas.
 /// </summary>
 private void RebuildVisuals()
 {
     // need to rebuild the index.
     _index           = null;
     _visualPositions = null;
     _visible         = Rect.Empty;
     _done            = false;
     foreach (FrameworkElement e in Children)
     {
         IVirtualChild n = e.GetValue(VirtualChildProperty) as IVirtualChild;
         if (n != null)
         {
             e.ClearValue(VirtualChildProperty);
             n.DisposeVisual();
         }
     }
     UpdateLayout();
     Children.Clear();
     InvalidateArrange();
     StartLazyUpdate();
 }
Пример #6
0
        /// <summary>
        /// Insert the visual for the child in the same order as is is defined in the
        /// VirtualChildren collection so the visuals draw on top of each other in the expected order.
        /// The trick is that GetNodesIntersecting returns the nodes in pretty much random order depending
        /// on how the QuadTree decides to break up the canvas.
        ///
        /// The thing we should avoid is a linear search through the potentially large collection of
        /// IVirtualChildren to compute its visible index which is why we have the _visualPositions map.
        /// We should also avoid a N*M algorithm where N is the number of nodes returned from GetNodesIntersecting
        /// and M is the number of children already visible.  For example, Page down in a zoomed out situation
        /// gives potentially high N and and M which would basically be an O(n2) algorithm.
        ///
        /// So the solution is to use the _visualPositions map to get the expected visual position index
        /// of a given IVirtualChild, then do a binary search through existing visible children to find the
        /// insertion point of the new child.  So this is O(Log M).
        /// </summary>
        /// <param name="child">The IVirtualChild to add visual for</param>
        public void EnsureVisual(IVirtualChild child)
        {
            if (child.Visual != null)
            {
                return;
            }

            FrameworkElement e = child.CreateVisual(this);

            e.SetValue(VirtualChildProperty, child);
            Rect bounds = child.Bounds;

            Canvas.SetLeft(e, bounds.Left);
            Canvas.SetTop(e, bounds.Top);

            // Get the correct absolute position of this child.
            int position = _visualPositions[child];

            // Now do a binary search for the correct insertion position based
            // on the visual positions of the existing visible children.
            UIElementCollection c = Children;
            int min = 0;
            int max = c.Count - 1;

            while (max > min + 1)
            {
                int           i = (min + max) / 2;
                UIElement     v = Children[i];
                IVirtualChild n = v.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    int index = _visualPositions[n];
                    if (index > position)
                    {
                        // search from min to i.
                        max = i;
                    }
                    else
                    {
                        // search from i to max.
                        min = i;
                    }
                }
                else
                {
                    // Any nodes without IVirtualChild should be behind the
                    // IVirtualChildren by definition (like the Backdrop).
                    min = i;
                }
            }

            // If 'max' is the last child in the collection, then we need to see
            // if we have a new last child.
            if (c.Count > 0 && max == c.Count - 1)
            {
                UIElement     v        = c[max];
                IVirtualChild maxchild = v.GetValue(VirtualChildProperty) as IVirtualChild;
                int           maxpos   = position;
                if (maxchild == null || position > _visualPositions[maxchild])
                {
                    // Then we have a new last child!
                    max++;
                }
            }
            if (max < 0)
            {
                c.Add(e);
            }
            else
            {
                c.Insert(max, e);
            }
        }
Пример #7
0
 /// <summary>
 /// Add a new IVirtualChild.  The VirtualCanvas will call CreateVisual on them
 /// when the Bounds of your child intersects the current visible view port.
 /// </summary>
 /// <param name="c"></param>
 public void AddVirtualChild(IVirtualChild child)
 {
     _children.Add(child);
 }
Пример #8
0
        /// <summary>
        /// Insert the visual for the child in the same order as is is defined in the 
        /// VirtualChildren collection so the visuals draw on top of each other in the expected order.
        /// The trick is that GetNodesIntersecting returns the nodes in pretty much random order depending 
        /// on how the QuadTree decides to break up the canvas.  
        /// 
        /// The thing we should avoid is a linear search through the potentially large collection of 
        /// IVirtualChildren to compute its visible index which is why we have the _visualPositions map.  
        /// We should also avoid a N*M algorithm where N is the number of nodes returned from GetNodesIntersecting 
        /// and M is the number of children already visible.  For example, Page down in a zoomed out situation 
        /// gives potentially high N and and M which would basically be an O(n2) algorithm.  
        /// 
        /// So the solution is to use the _visualPositions map to get the expected visual position index
        /// of a given IVirtualChild, then do a binary search through existing visible children to find the
        /// insertion point of the new child.  So this is O(Log M).  
        /// </summary>
        /// <param name="child">The IVirtualChild to add visual for</param>
        public void EnsureVisual(IVirtualChild child)
        {
            if (child.Visual != null)
            {
                return;
            }

            UIElement e = child.CreateVisual(this);
            e.SetValue(VirtualChildProperty, child);
            Rect bounds = child.Bounds;
            Canvas.SetLeft(e, bounds.Left);
            Canvas.SetTop(e, bounds.Top);

            // Get the correct absolute position of this child.
            int position = _visualPositions[child];

            // Now do a binary search for the correct insertion position based
            // on the visual positions of the existing visible children.
            UIElementCollection c = _content.Children;
            int min = 0;
            int max = c.Count - 1;
            while (max > min + 1)
            {
                int i = (min + max) / 2;
                UIElement v = _content.Children[i];
                IVirtualChild n = v.GetValue(VirtualChildProperty) as IVirtualChild;
                if (n != null)
                {
                    int index = _visualPositions[n];
                    if (index > position)
                    {
                        // search from min to i.
                        max = i;
                    }
                    else
                    {
                        // search from i to max.
                        min = i;
                    }
                }
                else
                {
                    // Any nodes without IVirtualChild should be behind the
                    // IVirtualChildren by definition (like the Backdrop).
                    min = i;
                }
            }

            // If 'max' is the last child in the collection, then we need to see
            // if we have a new last child.
            if (max == c.Count - 1)
            {
                UIElement v = c[max];
                IVirtualChild maxchild = v.GetValue(VirtualChildProperty) as IVirtualChild;
                int maxpos = position;
                if (maxchild == null || position > _visualPositions[maxchild])
                {
                    // Then we have a new last child!
                    max++;
                }
            }

            c.Insert(max, e);
        }
Пример #9
0
 /// <summary>
 /// Add a new IVirtualChild.  The VirtualCanvas will call CreateVisual on them
 /// when the Bounds of your child intersects the current visible view port.
 /// </summary>
 /// <param name="c"></param>
 public void AddVirtualChild(IVirtualChild child)
 {
     _children.Add(child);
 }