WPF Listbox Virtualization创建DisconnectedItems

Hus*_*lil 13 .net c# wpf virtualization

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

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

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

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

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

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

以下是画布代码的一部分:

/// <summary>
/// Arranges and virtualizes child element positionned explicitly.
/// </summary>
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));
    }
Run Code Online (Sandbox Code Playgroud)

Ádá*_*zay 9

我迟到了 6 年,但问题在 WPF 中仍未解决。是解决方案(解决方法)。

对 DataContext 进行自绑定,例如:

<Image DataContext="{Binding}" />
Run Code Online (Sandbox Code Playgroud)

这对我有用,即使对于非常复杂的 xaml。

  • 这在我的情况下不起作用,但让我找到了另一个解决方案:我将元素的“标签”设置为绑定,作为备份,因此即使数据上下文断开连接,我仍然可以访问真实的项目。例如,在 ListBoxItem 的样式中,我有这样的: `&lt;Setter Property="Tag" Value="{Binding}"/&gt;` (2认同)

Pau*_*hra 7

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

这是WPF 4中的已知错误

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

编辑:

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

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

  • 现在围绕 stackoverflow 的“Microsoft Connect 已停用”。干得好,微软( (6认同)