2010-07-20 6 views
1

J'ai un ListBox, et je dois mettre son ControlTemplate à un Virtualisation WrapPanel qui est une classe qui étend VirtualizingPanel, en utilisant un style qui ressemble à ceci:Pourquoi ItemContainerGenerator ne renvoie nulle?

<Style TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle"> 
       <Setter Property="Foreground" Value="White" /> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type ListBox}" > 
          <s:VirtualizingVerticalWrapPanel> 
          </s:VirtualizingVerticalWrapPanel> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 

Maintenant, dans la méthode privée de Virtualisation WrapPanel ci-dessous je tente d'accéder this.ItemContainerGenerator, mais je reçois valeur nulle, toute idée quel est le problème ??

private void RealizeFirstItem() 
{ 
    IItemContainerGenerator generator = this.ItemContainerGenerator; 
    GeneratorPosition pos = generator.GeneratorPositionFromIndex(0); 

    using (generator.StartAt(pos, GeneratorDirection.Forward)) 
    { 
     UIElement element = generator.GenerateNext() as UIElement; 

     generator.PrepareItemContainer(element); 

        this.AddInternalChild(element); 
    } 
} 
+0

"this.ItemContainerGenerator" Que cela signifie Listbox? – Ragunathan

+0

cela se réfère à Virtualiser WrapPanel, le Virtualrap WrapPanel est utilisé dans le ControlTemplate de la ListBox – simo

Répondre

7

Je pense que j'ai eu un problème similaire et cela a contribué:

var necessaryChidrenTouch = this.Children; 
IItemContainerGenerator generator = this.ItemContainerGenerator; 

... pour une raison que vous avez à la collection enfants « toucher » pour que le ItemContainerGenerator initialiser correctement.

+0

Vous ne savez pas pourquoi vous avez été downvoted, dans mon expérience, vous avez absolument raison. C'est un bug qui a été noté il y a cinq ans par les membres de l'équipe d'avalon. – Jordan0Day

+0

Parfait, merci! – Andy

-1

Ceci est parce que vous changé le modèle de la zone de liste, alors que u devrait avoir juste changé le ItemsPanel:

<ListBox> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <s:VirtualizingVerticalWrapPanel /> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
    </ListBox> 
0

Falck est la plupart du temps correct. En fait, vous devez référencer les 'InternalChildren' du panneau de la pile virtualisée. Le code décompilé de cette propriété est:

protected internal UIElementCollection InternalChildren 
    { 
     get 
     { 
      this.VerifyBoundState(); 
      if (this.IsItemsHost) 
      { 
       this.EnsureGenerator(); 
      } 
      else if (this._uiElementCollection == null) 
      { 
       this.EnsureEmptyChildren(this); 
      } 
      return this._uiElementCollection; 
     } 
    } 

Le « EnsureGenerator » fait le travail de faire en sorte qu'un générateur est disponible. Très mauvaise conception «juste à temps», IMO.

2

pour Windows 8.1 des applications Metro, le ItemContainerGenerator a été depricated et renvoie null. Nouveaux Apis:

ItemsControl.ItemContainerGenerator.ItemFromContainer = ItemsControl.ItemFromContainer

ItemsControl.ItemContainerGenerator.ContainerFromItem = ItemsControl.ContainerFromItem

ItemsControl.ItemContainerGenerator.IndexFromContainer = ItemsControl.IndexFromContainer

ItemsControl.ItemContainerGenerator. ContainerFromIndex = ItemsControl.ContainerFromIndex

http://msdn.microsoft.com/en-us/library/windows/apps/dn376326.aspx

+0

merci beaucoup monsieur – FatemehEbrahimiNik

0

Très probablement c'est un problème lié à la virtualisation afin ListBoxItem conteneurs sont générées uniquement pour les éléments actuellement visibles (par exemple https://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel(v=vs.110).aspx#Anchor_9)

Je vous suggère de passer à ListView au lieu de ListBox - il hérite de ListBox et il prend en charge la méthode ScrollIntoView() que vous pouvez utiliser pour contrôler la virtualisation;

targetListView.ScrollIntoView(itemVM); 
DoEvents(); 
ListViewItem itemContainer = targetListView.ItemContainerGenerator.ContainerFromItem(itemVM) as ListViewItem; 

(l'exemple ci-dessus utilise également la méthode statique DoEvents() expliquée plus en détail ici, WPF how to wait for binding update to occur before processing more code?)

Il y a quelques autres différences mineures entre les ListBox et ListView contrôles (What is The difference between ListBox and ListView) - qui ne devrait pas essentiellement affecter votre cas d'utilisation.

Questions connexes