【问题标题】:WPF Listbox Virtualization creates DisconnectedItemsWPF 列表框虚拟化创建 DisconnectedItems
【发布时间】:2012-12-26 07:32:47
【问题描述】:

我正在尝试使用 WPF 列表框创建图形控件。我创建了自己的 Canvas,它派生自 VirtualizingPanel,我自己处理项目的实现和虚拟化。

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

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

  • 首先创建列表框项 A。
  • ListBox 项目 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));
    }

【问题讨论】:

  • 你在回收容器吗?
  • @Blam:我想我不是,你说回收容器是什么意思?
  • 只需在 msdn 中搜索回收容器 msdn.microsoft.com/en-us/library/… 只是一个范围,也只是一个评论
  • @Blam:谢谢,我尝试使用 VirtualizingStackPanel 并打开容器回收。不幸的是我仍然有同样的问题,即:当项目被虚拟化时,正在生成 DisconnectedItems。

标签: c# .net wpf virtualization


【解决方案1】:

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

对 DataContext 进行自绑定,例如:

<Image DataContext="{Binding}" />

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

【讨论】:

  • 美女!修复了我与触发器和切换模板相关的问题。
  • 这在我的情况下不起作用,但让我找到了另一个解决方案:我将元素的 Tag 设置为绑定,作为备份,所以即使在数据上下文已断开连接。例如。在 ListBoxItem 的风格中,我有这个:&lt;Setter Property="Tag" Value="{Binding}"/&gt;
  • 不,你一点也不迟到!!早几年,印象深刻。我的问题是调用NotifyCollectionChanged 进行排序中使用的移动操作,我认为这不是开箱即用的,但我的解决方法是手动执行删除/插入,并且在重新插入时得到{{DisconnectedItem}}
【解决方案2】:

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

这是 WPF 4 中的一个已知错误

请参阅this link for known bug,它还有一个您可以申请的解决方法。

“您可以通过保存参考来使您的解决方案更加强大 第一次看到哨兵对象 {DisconnectedItem}, 然后与之后保存的值进行比较。

我们应该公开测试 {DisconnectedItem} 的方法,但是 它从裂缝中溜走了。我们将在未来的版本中解决这个问题,但是 现在你可以指望有一个独特的事实 {DisconnectedItem} 对象。”

【讨论】:

  • “Microsoft Connect 已停用”现在围绕 stackoverflow。干得好,微软(
猜你喜欢
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 2013-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多