Die WPF-Listbox-Virtualisierung erstellt DisconnectedItems

Ich versuche, ein Graph-Steuerelement mit einer WPF-ListBox zu erstellen. Ich habe mein eigenes Canvas erstellt, das aus einem VirtualizingPanel stammt, und kümmere mich selbst um die Realisierung und Virtualisierung von Objekten.

Das Elementfenster der Listbox wird dann als meine benutzerdefinierte virtualisierte Zeichenfläche festgelegt.

Das Problem, auf das ich stoße, tritt in dem folgenden Szenario auf:

ListBox Item A wird zuerst erstellt.Das ListBox-Element B wird rechts von Element A auf der Zeichenfläche erstellt.ListBox-Element A wird zuerst virtualisiert (durch Verschieben außerhalb der Ansicht).ListBox Item B wird als zweites virtualisiert (erneut durch Verschieben außerhalb der Ansicht).Bring ListBox Item A und B in Sicht (d. H. Realisiere sie)Mit Snoop stelle ich fest, dass die ListBox jetzt 3 Elemente enthält, von denen eines ein "DisconnectedItem" ist, das sich direkt unter ListBox-Element B befindet.

Wodurch wird dieses "DisconnectedItem" erstellt? Wenn ich zuerst B und dann A virtualisieren würde, würde dieses Element nicht erstellt. Meine Theorie ist, dass das Virtualisieren von Elementen, die anderen Elementen in einer ListBox vorangehen, dazu führt, dass untergeordnete Elemente getrennt werden.

Das Problem wird noch deutlicher, wenn ich ein Diagramm mit Hunderten von Knoten verwende, da ich beim Schwenken Hunderte von nicht verbundenen Elementen habe.

Hier ist ein Teil des Codes für die Zeichenfläche:

/// <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));
    }

Antworten auf die Frage(1)

Ihre Antwort auf die Frage