Plus d'explications, s'il vous plaît!
Alors que toutes les réponses ci-dessus sont techniquement correctes, je pense qu'elles n'illustrent pas comment IsItemsPanel
se rapporte au ControlTemplate
et à la présence (ou à l'absence) d'un ItemsPresenter
et de la propriété correspondante ItemsPanel
qu'il utilise. Cette réponse tentera d'éclairer ces aspects et espère clarifier quand vous devriez, ou ne devriez pas utiliser chacun.
ItemsControls, Panels et IsItemsHost, Oh mon dieu!
Un ItemsControl
est simplement un contrôle qui affiche une collection d'éléments. Il le fait en générant d'abord des conteneurs individuels* pour représenter visuellement les éléments, puis il remet ces conteneurs à un panel spécifique pour les agencer pour être affichés à l'écran. Lorsque des éléments sont ajoutés ou supprimés, l' ItemsControl
ajoute ou supprime les conteneurs correspondants du panel selon le besoin.
* Note: Si un élément est déjà une instance du type de conteneur (tel que déterminé par le résultat du remplacement de la méthode IsItemItsOwnContainer du ItemsControl
) -- c'est-à-dire, vous ajoutez une instance de ListBoxItem
à la collection Items
d'une ListBox
-- cet élément est simplement transmis en l'état directement au panel, agissant comme son propre conteneur.
Le panel spécifique utilisé pour héberger et agencer les conteneurs est le premier panel trouvé dans le modèle de contrôle de l' ItemControl
qui a sa propriété IsItemsHost
définie sur 'True'.
Il y a deux façons de spécifier lequel il s'agit:
-
En insérant un ItemsPresenter
dans le ControlTemplate
pour servir de substitut au panel spécifié par la propriété ItemsPanel
. (C'est la manière la plus courante.)
-
En insérant directement un Panel
dans le ControlTemplate
et en définissant explicitement sa propriété IsItemsHost
sur True
.
Mais lequel utiliser et pourquoi? Continuez à lire pour le découvrir!
ItemsPresenter - "Faites comme bon vous semble!"
Dans un ControlTemplate
typique pour un ItemsControl
tel qu'une ListBox
, le modèle spécifie un ItemsPresenter
quelque part à l'intérieur de celui-ci. Voici un extrait simplifié montrant comment il est utilisé:
Comme vous pouvez le voir, il y a un ItemsPresenter
spécifié à l'intérieur d'un ScrollViewer
au milieu du modèle. Ce que vous ne voyez cependant pas, c'est un panel réel pour agencer les éléments.
Alors, s'il n'y a pas de panel défini dans le modèle, d'où vient-il? C'est là que la propriété ItemsPanel
entre en jeu. Comme son nom l'indique, cette propriété définit quel panel sera utilisé pour héberger et agencer les éléments. Cependant, elle ne dit pas où ce panel apparaît dans le ControlTemplate
.
Cela nous ramène à l'ItemsPresenter
. En bref, c'est un substitut qui dit essentiellement "Lorsque la propriété ItemsPanel
est définie, j'insérerai ce panel ici et définirai automatiquement son IsItemsHost
sur True
."
L'avantage d'utiliser un ItemsPresenter
dans le modèle de votre ItemsControl
est que vous rendez très facile pour les consommateurs de votre contrôle de remplacer ce panel sans avoir à restructurer complètement l'intégralité de votre contrôle.
IsItemsHost - "A ma manière ou la route!"
Cependant, que se passe-t-il si vous ne souhaitez pas que quelqu'un puisse remplacer votre panel parce que votre contrôle dépend d'une implémentation de panel personnalisée et que tout autre chose cassera la fonctionnalité? Dans ce cas, vous n'utilisez pas un ItemsPresenter
dans votre modèle. Vous devez plutôt spécifier le panel exact que vous souhaitez utiliser.
C'est là que la propriété IsItemsHost
entre en jeu. Lorsqu'elle est définie sur un panel dans le ControlTemplate
, elle indique à cet ItemsControl
d'utiliser ce panel spécifique pour héberger les conteneurs générés, indépendamment de ce que la propriété ItemsPanel
est définie. La propriété ItemsPanel
est essentiellement ignorée.
Un autre avantage de spécifier le panel directement dans le modèle est que vous pouvez ensuite le nommer et y accéder comme n'importe quelle autre partie du modèle.
Voici le même exemple que ci-dessus, mais au lieu d'un ItemsPresenter
, il code en dur un SpecializedPanel
pour agencer les éléments. Nous indiquons que c'est le panel que nous voulons utiliser pour héberger les éléments en définissant sa propriété IsItemsHost
sur True
et enfin, lui donnons un nom pour y accéder directement depuis le code.
Dans ce cas, puisque le modèle n'utilise pas un ItemsPresenter
et inclut directement un panel avec sa propriété IsItemsHost
définie sur True
, il n'y a aucun moyen pour l'utilisateur de remplacer ce panel autrement que par le remplacement complet du ControlTemplate
entier. (Comme mentionné précédemment, la propriété ItemsPanel
est ignorée.)
En concluant...
Pour récapituler, si vous êtes l'auteur d'un contrôle et souhaitez donner aux consommateurs de votre contrôle la flexibilité de remplacer le panel utilisé pour agencer vos éléments, alors définissez votre modèle pour votre ItemsControl
en utilisant un ItemsPresenter
. Assurez-vous également de définir la propriété ItemsPanel
dans le modèle pour spécifier un panel par défaut.
Cependant, si vous souhaitez 'verrouiller' le panel utilisé par votre contrôle, alors n'utilisez pas un ItemsPresenter
dans le ControlTemplate
. Au lieu de cela, spécifiez le panel spécifique que vous souhaitez utiliser directement dans le modèle, puis définissez sa propriété IsItemsHost
sur True
.
Note: Il existe techniquement un troisième scénario, qui est probablement plus courant: Vous n'êtes pas un auteur de contrôle créant quelque chose à être consommé par d'autres utilisateurs, mais vous restructurez simplement un ItemsControl
(comme par exemple une ListBox
) pour une utilisation spécialisée dans votre propre application.
Dans ce cas, étant donné que vous êtes le consommateur ultime du contrôle, il est fort probable que vous n'aurez pas à vous soucier d'autres consommateurs en aval ayant besoin de changer le panel, il est tout à fait acceptable de simplement spécifier le panel directement dans votre modèle (encore une fois, en définissant IsItemsHost
à true) et de ne pas vous soucier d'utiliser un ItemsPresenter
et sa propriété associée ItemsPanel
car cette dernière, bien que valide, ajouterait simplement une complexité inutile sans aucun réel bénéfice.
En espérant que cela clarifie exactement ce qui se passe.