2013-01-11 120 views
12

我試圖創建使用WPF列表框一個圖表控件。我創建了自己的Canvas,它來自VirtualizingPanel,我自己處理項目的實現和虛擬化。WPF列表框虛擬化創建DisconnectedItems

的ListBox的項目小組,然後設置爲我的自定義虛擬畫布。

我遇到的問題發生在以下情形:首次創建

  • 列表框A項。
  • 列表框項目B創建在畫布上項目A的右側。
  • 列表框項目A首先被虛擬化(通過將其平移到視圖外)。
  • 列表框項目B被虛擬化第二(再次通過平移它的視圖)。
  • 帶上列表框項目A和B的視圖(即:實現它們)
  • 使用snoop,我檢測到列表框具有現在3項,其中之一是一個「DisconnectedItem」直接位於列表框項目B.下方

是什麼原因導致這種「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)); 
    } 
+0

您是否在回收容器? – Paparazzi

+0

@Blam:我不認爲我是,回收容器是什麼意思? –

+0

只是在MSDN中查找回收容器http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizationmode.aspx只是一個範圍,但也只是一個評論 – Paparazzi

回答

7

每當容器從視覺樹中刪除它的使用的,或者是因爲相應的項目已被刪除,或收集被刷新,或容器從屏幕上滾動並重新虛擬化。

這是WPF 4

一個已知的bug見this link for known bug,它也有可能能夠應用一種變通方法。

編輯:

「可以通過保存到定點對象{DisconnectedItem}你第一次看到它的參考,然後對後保存的值進行比較,讓您的解決方案多了幾分穩健

我們應該做一個公開的方式來測試{DisconnectedItem},但它通過裂縫下滑,我們會解決這個問題在將來的版本,但現在你可以在這樣的事實,有一個獨特的{DisconnectedItem}對象計數。 「