/// <summary> /// Gets the realized <see cref="Visual"/> associated with an item if the <see cref="Visual"/> has been realized already. /// </summary> /// <param name="item">The item associated with the returned <see cref="Visual"/>.</param> /// <returns>The <see cref="Visual"/> created in response to <see cref="RealizeItem"/> with the given item, or null if none has been created.</returns> public Visual VisualFromItem(ISpatialItem item) { Visual visual = null; this.visualMap.TryGetValue(item, out visual); return(visual); }
/// <summary> /// RealizeItems from the itemsToRealize enumerable upto the maxItemsToRealize limit. /// </summary> /// <param name="itemsToRealize">items to realize</param> /// <param name="realizedItems">Set of Realized Items</param> /// <param name="maxItemsToRealize">Max limit of items to realize</param> /// <returns>count of items realized.</returns> private int RealizeItems(IEnumerator <ISpatialItem> itemsToRealize, HashSet <ISpatialItem> realizedItems, int maxItemsToRealize) { int itemsRealized = 0; // This has to happen again because of the lazy throttling that can happen after RealizeOverride has returned. IVisualFactory f = VisualFactory ?? this.defaultFactory; f.BeginRealize(); // Realize n items where n <= this.realizationQuantum. while (itemsRealized < maxItemsToRealize && itemsToRealize.MoveNext()) { ISpatialItem item = itemsToRealize.Current; Visual realizedVisual = RealizeItem(item, false); if (realizedVisual != null) { itemsRealized++; realizedItems.Add(item); } } f.EndRealize(); return(itemsRealized); }
/// <summary> /// Forces the item to be virtualized. /// </summary> public void ForceVirtualizeItem(ISpatialItem item) { Visual visual = VisualFromItem(item); if (visual != null) { ForceVirtualizeItem(item, visual); } }
private void ForceVirtualizeItem(ISpatialItem item, Visual visual) { this.visualChildren.Remove(visual); RemoveVisualChild(visual); this.visualMap.Remove(item); visual.ClearValue(RealizedItemPropertyKey); // This kills performance of scrolling and zooming because it adds a ton of extra cleanup work. // But we don't know why it was added yet, so we'll see what breaks when we remove it. // visual.ClearValue(FrameworkElement.DataContextProperty); itemsRemoved++; }
/// <summary> /// Destroys and/or recycles a visual from an item and removes it as a visual child. /// </summary> /// <param name="item">The item to remove the visual for.</param> private void VirtualizeItem(ISpatialItem item) { if (item == null) { throw new ArgumentNullException("item"); } Visual visual; if (this.visualMap.TryGetValue(item, out visual)) { if (this.ShouldVirtualize(item)) { this.ForceVirtualizeItem(item, visual); } } }
/// <summary> /// Arranges the content of a <see cref="VirtualCanvas"/> element. /// </summary> /// <param name="finalSize">The size that this <see cref="VirtualCanvas"/> element should use to arrange its child elements.</param> /// <returns>A <see cref="Size"/> that represents the arranged size of this <see cref="VirtualCanvas"/> element and its descendants.</returns> protected override Size ArrangeOverride(Size finalSize) { using (this.BeginUpdate()) { try { if (Measuring != null) { Measuring(this, EventArgs.Empty); } doingLayout = true; foreach (Visual visual in this.VisualChildren) { UIElement child = visual as UIElement; if (child != null) { ISpatialItem spatialItem = (ISpatialItem)ItemFromVisual(child); Rect desiredBounds = new Rect(spatialItem.Bounds.TopLeft, child.DesiredSize); desiredBounds.X = desiredBounds.X.AtLeast(Single.MinValue / 2); desiredBounds.Y = desiredBounds.Y.AtLeast(Single.MinValue / 2); desiredBounds.Width = desiredBounds.Width.AtMost(Single.MaxValue); desiredBounds.Height = desiredBounds.Height.AtMost(Single.MaxValue); child.Arrange(desiredBounds); child.RaiseEvent(new RoutedEventArgs(FrameworkElement.SizeChangedEvent)); ZoomWatcher.TickleZoomable(this.Scale, child); } } if (Measured != null) { Measured(this, EventArgs.Empty); } } finally { doingLayout = false; } return(finalSize); } }
/// <summary> /// Determines if the item should be virtualized. /// </summary> /// <returns>True if the item should be virtualized.</returns> private bool ShouldVirtualize(ISpatialItem item) { if (this.Items == null || !item.IsVisible) { return(true); } UIElement visual = VisualFromItem(item) as UIElement; if (visual == null) { return(true); } else if (visual.IsMouseCaptureWithin || visual.IsKeyboardFocusWithin || visual.IsFocused) { return(false); } return(VisualFactory == null || VisualFactory.Virtualize(visual)); }
/// <summary> /// Measures the child elements of a <see cref="VirtualCanvas"/> in anticipation of arranging them during the <see cref="ArrangeOverride"/> pass. /// </summary> /// <param name="availableSize">An upper limit <see cref="Size"/> that should not be exceeded.</param> /// <returns>A <see cref="Size"/> that represents the size that is required to arrange child content.</returns> protected override Size MeasureOverride(Size availableSize) { Size finalSize = new Size(); doingLayout = true; try { if (Measuring != null) { Measuring(this, EventArgs.Empty); } // Currently we are only enumerating actual visuals to get the extent that SizeToContent sizes to. // We may want to think about changing the definition of SizeToContent to account for virtualized items too. foreach (Visual visual in this.VisualChildren) { UIElement child = visual as UIElement; if (child != null) { // Initialize child constraint to infinity. We need to get a "natural" size for the child in absence of constraint. Size infiniteConstraint = new Size(Double.PositiveInfinity, Double.PositiveInfinity); child.Measure(infiniteConstraint); ISpatialItem spatial = ItemFromVisual(child) as ISpatialItem; if (spatial != null && this.ComputeOutlineGeometry) { spatial.OnMeasure(child); } } } if (Measured != null) { Measured(this, EventArgs.Empty); } } finally { doingLayout = false; } return(finalSize); }
private void HandleLeftButtonUp(IPointerEventArgs e) { if (m_Pointer != null) { ISpatialDocument doc = Scene?.Document; if (doc != null) { m_Hits.Clear(); Coordinate pos = Scene.ViewToWorld(m_Position); doc.HitTest(pos.X, pos.Y, 5, 1 / Scene.Scale, m_HitTestSpec, m_Hits); bool multi = e.KeyModifiers.HasFlag(KeyModifiers.Shift); if (m_Hits.Count == 1) { if (!multi) { doc.DeselectAll(); } var pair = m_Hits.First(); IItemsLayer layer = pair.Value; ISpatialItem item = pair.Key; if (layer.IsItemSelected(item)) { if (multi) { layer.DeselectItem(item); } } else { layer.SelectItem(item); } } else { doc.DeselectAll(); } } } }
/// <summary> /// Determines if the item should be realized. /// </summary> /// <returns>True if the item should be realized.</returns> internal static bool ShouldRealize(ISpatialItem item) { return(item.IsVisible); }
/// <summary> /// Creates a <see cref="Visual"/> for an item and adds it as a visual child. /// </summary> /// <param name="item">The item to create a visual for.</param> /// <param name="force">Whether to tell the factory to force construction of this shape</param> /// <returns>The <see cref="Visual"/> created for the item.</returns> internal Visual RealizeItem(ISpatialItem item, bool force) { if (item == null) { throw new ArgumentNullException("item"); } if (!ShouldRealize(item)) { return(null); } Visual visual; if (!this.visualMap.TryGetValue(item, out visual)) { var f = VisualFactory; object dataItem = item.DataItem; visual = f.Realize(dataItem, force); if (visual != null) { visual.SetValue(RealizedItemPropertyKey, item); this.visualChildren.Add(visual, item.ZIndex); AddVisualChild(visual); // Set the data context after visual has been added to the tree so that the // visual DataContextChanged event handler can find resources and other things // that are inherited up the UI element hierarchy. var element = visual as FrameworkElement; if (element != null) { element.DataContext = dataItem; } this.visualMap.Add(item, visual); itemsAdded++; InvalidateMeasure(); InvalidateArrange(); if (visual is FrameworkElement e) { e.InvalidateVisual(); } } } else { bool updated = this.visualChildren.Update(visual, item.ZIndex); if (updated) { itemsChanged++; // this is the only way we can find to force WPF to redraw everything in the right order. // Somehow, InvalidateVisual is not enough. SetChangingZIndex(visual, true); try { this.RemoveVisualChild(visual); this.AddVisualChild(visual); } finally { visual.ClearValue(ChangingZIndexProperty); } } } return(visual); }
/// <summary> /// Creates a <see cref="Visual"/> for an item and adds it as a visual child. /// </summary> /// <param name="item">The item to create a visual for.</param> /// <returns>The <see cref="Visual"/> created for the item.</returns> public Visual RealizeItem(ISpatialItem item) { return(RealizeItem(item, true)); }