2013-01-11 18 views
12

Próbuję utworzyć formant wykresu przy użyciu listwy listy WPF. Stworzyłem własne płótno, które pochodzi z VirtualizingPanel, a ja sam zajmuję się realizacją i wirtualizacją przedmiotów.Wirtualizacja WPF Listbox tworzy DisconnectedItems

Panel elementów "listbox" zostanie ustawiony jako moje niestandardowe płótno zwirtualizowane.

Problem mam napotykając występuje w następującym scenariuszu:

  • ListBox Pozycja A tworzony jest pierwszy.
  • ListBox Pozycja B jest tworzona na prawo od pozycji A na płótnie.
  • Element ListBox jest najpierw zwirtualizowany (poprzez przesunięcie go poza obszar widoku).
  • ListBox Pozycja B jest zwirtualizowana jako druga (ponownie poprzez przesunięcie jej poza obszar widoku).
  • Doprowadzić ListBox pozycja A i B w związku (tj zrealizować je)
  • Korzystanie Snoop, wykryć, że ListBox ma teraz 3 elementów, jednym z nich jest to „DisconnectedItem” znajdujący się bezpośrednio pod ListBox Pozycja B.

Co powoduje utworzenie "DisconnectedItem"? Gdybym najpierw wirtualizował B, a następnie A, ten element nie zostałby utworzony. Moja teoria mówi, że wirtualizacja elementów, które poprzedza inne elementy ListBox, powoduje, że dzieci są odłączone.

Problem jest jeszcze bardziej widoczny za pomocą wykresu z setkami węzłów, ponieważ kończę z setkami rozłączonych elementów podczas przesuwania.

Oto fragment kodu na płótnie:

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

Czy recyklingujesz pojemnik? – Paparazzi

+0

@Blam: Nie sądzę, że jestem, co masz na myśli przez recykling pojemnika? –

+0

Po prostu wyszukaj msdn na pojemnik na recykling http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizationmode.aspx Wystarczy zasięg, ale także tylko komentarz – Paparazzi

Odpowiedz

7

Jest używany, gdy pojemnik jest usuwany z drzewa wizualnej, albo dlatego, że odpowiednia pozycja została usunięta lub zbiór był odświeżony, lub kontener został przewinięty z ekranu i ponownie zwirtualizowany.

To znany błąd w WPF 4

Zobacz this link for known bug, ma też obejście może być w stanie zastosować.

EDIT:.

„Można dokonać rozwiązanie trochę bardziej wytrzymałe zapisując odniesienie do obiektu wartowniczego {DisconnectedItem} Gdy pierwszy raz go zobaczyć, a następnie porównanie z zapisaną wartością po tym

Powinniśmy publicznie przetestować {DisconnectedItem}, ale przebrnęliśmy przez pęknięcia. Naprawimy to w przyszłej wersji, ale na razie możesz liczyć na fakt, że istnieje wyjątkowy obiekt {DisconnectedItem}. "