2010-03-22 5 views
1

Je veux mettre en œuvre un Canvas personnalisé qui recycle des conteneurs lorsqu'il est utilisé comme ItemsPanel. Donc, j'ai dérivé de VirtualizingPanel et remplacer les ArrangeOverride et MeasureOverride. Je fais la génération en MeasureOverride comme ceci:WPF conteneur d'articles de recyclage

var children = base.InternalChildren; 

var itemsControl = ItemsControl.GetItemsOwner(this); 
var itemsCount = itemsControl.Items.Count; 

IItemContainerGenerator generator = itemsControl.ItemContainerGenerator; 

var startPos = generator.GeneratorPositionFromIndex(0); 

using (generator.StartAt(startPos, GeneratorDirection.Forward, true)) 
{ 
    for (int i = 0; i < itemsCount; i++) 
    { 
     bool isNewlyRealized; 

     var child = generator.GenerateNext(out isNewlyRealized) as UIElement; 

     if (isNewlyRealized) 
     { 
      base.AddInternalChild(child); 
      generator.PrepareItemContainer(child); 
     } 

     child.Measure(constraint); 
    } 
} 

Ce que je ne sais pas comment faire le recyclage. J'ai essayé quelque chose comme le suivant:

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs e) 
{ 
    switch (e.Action) 
    { 
     case NotifyCollectionChangedAction.Remove: 
     case NotifyCollectionChangedAction.Replace: 
     case NotifyCollectionChangedAction.Move: 
      IRecyclingItemContainerGenerator generator = ItemsControl.GetItemsOwner(this).ItemContainerGenerator; 
      generator.Recycle(e.Position, e.ItemUICount); 
      RemoveInternalChildRange(e.Position.Index, e.ItemUICount); 
      break; 
    } 
} 

Mais cela ne fonctionne pas. Une idée de comment faire cela?

Répondre

3

Regardez ici: http://blogs.claritycon.com/blogs/lee_roth/default.aspx

je faire du recyclage de la manière suivante:

En OnItemsChanged, je ne convoquent que RemoveInternalChildRange:

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args) 
    { 
     switch (args.Action) 
     { 
     case NotifyCollectionChangedAction.Remove: 
     case NotifyCollectionChangedAction.Replace: 
      RemoveInternalChildRange(args.Position.Index, args.ItemUICount); 
      break; 
     case NotifyCollectionChangedAction.Move: 
      RemoveInternalChildRange(args.OldPosition.Index, args.ItemUICount); 
      break; 
     } 
    } 

dans la mesure prioritaire, j'ai d'abord ajouter de nouveaux éléments, puis J'enlève les anciens. Si vous utilisez le recyclage, vous devez savoir que le nouveau drapeau obtenu en appelant GenerateNext est également faux si vous obtenez un conteneur recyclé.

Ici, nous ajoutons de nouveaux articles:

GeneratorPosition start = ItemContainerGenerator.GeneratorPositionFromIndex(iFirstItemIndex); 
     int iChildIndex = (start.Offset == 0) ? start.Index : start.Index + 1; 
     using (ItemContainerGenerator.StartAt(start, GeneratorDirection.Forward, true)) 
     { 
     for (int i = iFirstItemIndex; i <= iLastItemIndex; i++, iChildIndex++) 
     { 
      bool bNew; 
      UIElement element = (UIElement)ItemContainerGenerator.GenerateNext(out bNew); 
      //If we get a new instance 
      if (bNew) 
      { 
      if (iChildIndex >= Children.Count) AddInternalChild(element); 
      else InsertInternalChild(iChildIndex, element); 
      ItemContainerGenerator.PrepareItemContainer(element); 
      } 
      //If we get a recycled element 
      else if (!InternalChildren.Contains(element)) 
      { 
      InsertInternalChild(iChildIndex, element); 
      ItemContainerGenerator.PrepareItemContainer(element); 
      } 
      element.Measure(...); 
     } 
     } 

Après avoir ajouté des articles que nous supprimer les anciens objets:

for (int i = Children.Count - 1; i >= 0; i--) 
     { 
     GeneratorPosition childGeneratorPosition = new GeneratorPosition(i, 0); 
     int iIndex = ItemContainerGenerator.IndexFromGeneratorPosition(childGeneratorPosition); 
     if (iIndex < iFirstItemIndex || iIndex > iLastItemIndex) 
     { 
      //remove() calls ItemContainerGenerator.remove() OR recycle(). Both works. 
      remove(childGeneratorPosition, 1); 
      RemoveInternalChildRange(i, 1); 
     } 
     } 

J'espère que je pourrais vous aider.

+0

En fait, si vous faites du recyclage, vous devriez appeler votre code de 'nettoyage' (votre dernier bloc de code) avant de générer les nouveaux conteneurs. C'est parce que vous voulez recycler les contenants disponibles * avant * ils sont nécessaires, pas après. Enregistre quelques créations inutiles. – MarqueIV

+2

Le lien n'est plus disponible. – Djof

Questions connexes