2010-10-01 4 views
7

Je suis capable d'utiliser un ItemTemplate dans ItemsControl pour rendre des éléments dans un format spécifique. Toutefois, si l'un des éléments de ItemsControl se trouve être, par exemple, un TextBox, ce TextBox est rendu plutôt qu'une instance de ItemsTemplate. D'après ce que je peux dire, ceci est vrai pour tout FrameworkElement. Est-ce le comportement prévu pour un ItemsControl, ou est-ce que je fais quelque chose de façon incorrecte?Pourquoi ItemsControl n'utilise pas mon ItemTemplate?

Un exemple:

<ItemsControl> 
    <ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Grid Margin="5"> 
     <Rectangle Fill="Blue" Height="20" Width="20" /> 
     </Grid> 
    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
    <ItemsControl.Items> 
    <sys:Object /> 
    <TextBox /> 
    <sys:Object /> 
    <Rectangle Fill="Red" Height="20" Width="20" /> 
    </ItemsControl.Items> 
</ItemsControl> 

Je prévu cette option pour afficher quatre rectangles bleus. Je pensais que chaque fois qu'un ItemTemplate a été défini, chaque élément de la collection est rendu comme une instance du modèle. Cependant, dans ce cas, le rendu est le suivant: un rectangle bleu suivi d'un TextBox suivi d'un rectangle bleu suivi d'un rectangle rouge.

+0

Je devine que ce comportement est prévu et est destiné à permettre aux développeurs d'ajouter des contrôles spéciaux à usage unique. Par exemple, je pourrais utiliser ceci pour ajouter un bouton à un ComboBox qui efface la sélection, ou je pourrais mettre un TextBox dans un ListBox qui filtre la collection spécifiée par ItemsSource. J'aimerais entendre que quelqu'un a une réponse officielle pour ce comportement parce que je l'ai trouvé contre-intuitif à l'utilisation d'un ItemTemplate. – Drew

+0

Bonne question et bonne réponse d'Anthony, merci les gars. – Golvellius

Répondre

12

Le ItemsControl comporte un élément protégé IsItemItsOwnContainerOverride qui reçoit un objet à partir de la collection d'éléments et renvoie true si cet objet peut être ajouté directement dans le panneau articles sans un conteneur généré (et donc être templated).

L'implémentation de base renvoie true pour tout objet dérivé de UIElement.

Pour obtenir le comportement que vous attendez, vous devez hériter de ItemsControl et remplacer cette méthode et renvoyer toujours false. Malheureusement, ce n'est pas la fin de la question. L'implémentation par défaut de PrepareContainerForItemOverride ne reste attribue pas le ItemTemplate au conteneur si l'élément est un UIElement si vous devez remplacer cette méthode ainsi: -

protected override bool IsItemItsOwnContainerOverride(object item) 
    { 
     return false; 
    } 


    protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
    { 
     base.PrepareContainerForItemOverride(element, item); 
     ((ContentPresenter)element).ContentTemplate = ItemTemplate; 
    } 
+1

À partir de 2015, ils pourraient avoir réparé la deuxième partie. Avec WPF dans .NET 4.5.1, si je renvoie 'false' pour' IsItemItsOwnContainerOverride ', le modèle semble être défini sur le conteneur d'éléments. –

2

Je ne fais que spéculer ici, mais je parie que c'est le comportement qui vit à l'intérieur du ItemContainerGenerator. Je parie que le ItemContainerGenerator regarde un article, et si c'est un UIElement il dit, "cool, le conteneur de l'article a été généré, je vais le retourner" et si ce n'est pas, il dit, "Je ferais mieux de générer un conteneur pour cet article Où est le DataTemplate? "

Questions connexes