WPF Listbox Virtualization创建DisconnectedItems

我正在尝试使用WPF ListBox创建Graph控件。 我创建了自己的Canvas,它来自VirtualizingPanel,我自己处理项目的实现和虚拟化。

然后将列表框的项面板设置为我的自定义虚拟化canvas。

我遇到的问题发生在以下场景中:

  • 首先创建ListBox项目A.
  • 列表框项目B在canvas上的项目A的右侧创建。
  • 列表框项目A首先被虚拟化(通过将其平移到视图之外)。
  • ListBox项目B被虚拟化为第二个(再次通过将其平移到视图之外)。
  • 将ListBox项目A和B置于视图中(即:实现它们)
  • 使用Snoop,我检测到ListBox现在有3个项目,其中一个是直接位于ListBox项目B下面的“DisconnectedItem”。

是什么导致了这个“DisconnectedItem”的创建? 如果我首先虚拟化B,然后是A,则不会创建此项目。 我的理论是,虚拟化ListBox中其他项之前的项会导致子项断开连接。

使用包含数百个节点的图表时问题更加明显,因为当我平移时,我最终会收到数百个断开连接的项目。

以下是canvas代码的一部分:

///  /// Arranges and virtualizes child element positionned explicitly. ///  public class VirtualizingCanvas : VirtualizingPanel { (...) protected override Size MeasureOverride(Size constraint) { ItemsControl itemsOwner = ItemsControl.GetItemsOwner(this); // For some reason you have to "touch" the children collection in // order for the ItemContainerGenerator to initialize properly. var necessaryChidrenTouch = Children; IItemContainerGenerator generator = ItemContainerGenerator; IDisposable generationAction = null; int index = 0; Rect visibilityRect = new Rect( -HorizontalOffset / ZoomFactor, -VerticalOffset / ZoomFactor, ActualWidth / ZoomFactor, ActualHeight / ZoomFactor); // Loop thru the list of items and generate their container // if they are included in the current visible view. foreach (object item in itemsOwner.Items) { var virtualizedItem = item as IVirtualizingCanvasItem; if (virtualizedItem == null || visibilityRect.IntersectsWith(GetBounds(virtualizedItem))) { if (generationAction == null) { GeneratorPosition startPosition = generator.GeneratorPositionFromIndex(index); generationAction = generator.StartAt(startPosition, GeneratorDirection.Forward, true); } GenerateItem(index); } else { GeneratorPosition itemPosition = generator.GeneratorPositionFromIndex(index); if (itemPosition.Index != -1 && itemPosition.Offset == 0) { RemoveInternalChildRange(index, 1); generator.Remove(itemPosition, 1); } // The generator needs to be "reseted" when we skip some items // in the sequence... if (generationAction != null) { generationAction.Dispose(); generationAction = null; } } ++index; } if (generationAction != null) { generationAction.Dispose(); } return default(Size); } (...) private void GenerateItem(int index) { bool newlyRealized; var element = ItemContainerGenerator.GenerateNext(out newlyRealized) as UIElement; if (newlyRealized) { if (index >= InternalChildren.Count) { AddInternalChild(element); } else { InsertInternalChild(index, element); } ItemContainerGenerator.PrepareItemContainer(element); element.RenderTransform = _scaleTransform; } element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); } 

每当从可视树中删除容器时都会使用它,因为相应的项目已被删除,或者集合已刷新,或者容器已从屏幕滚动并重新虚拟化。

这是WPF 4中的已知错误

有关已知错误 ,请参阅此链接 ,它还有一个您可以应用的解决方法。

编辑:

“通过在第一次看到它时保存对标记对象{DisconnectedItem}的引用,然后在此之后与保存的值进行比较,您可以使解决方案更加健壮。

我们应该采用公开的方式来测试{DisconnectedItem},但它已经滑过了裂缝。 我们将在未来的版本中修复它,但是现在你可以指望有一个独特的{DisconnectedItem}对象。“