Puis-je utiliser un Modèle différent de l'élément sélectionné dans un WPF ComboBox que pour les éléments dans la liste déroulante de la partie?
J'ai un WPF zone de liste déroulante qui est rempli avec, disons, le Client ne s'y oppose. J'ai un DataTemplate:
<DataTemplate DataType="{x:Type MyAssembly:Customer}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Address}" />
</StackPanel>
</DataTemplate>
De cette façon, quand j'ouvre ma ComboBox, je peux voir les différents Clients avec leur Nom et, en dessous, l'Adresse.
Mais lorsque je sélectionne un Client, je ne veux afficher le Nom dans la zone de liste déroulante. Quelque chose comme:
<DataTemplate DataType="{x:Type MyAssembly:Customer}">
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
Puis-je choisir un autre Modèle pour l'élément sélectionné dans une liste déroulante?
Solution
Avec l'aide de la réponse, je l'ai résolu comme ceci:
<UserControl.Resources>
<ControlTemplate x:Key="SimpleTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}" />
</StackPanel>
</ControlTemplate>
<ControlTemplate x:Key="ExtendedTemplate">
<StackPanel>
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{Binding Address}" />
</StackPanel>
</ControlTemplate>
<DataTemplate x:Key="CustomerTemplate">
<Control x:Name="theControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
<Setter TargetName="theControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
Alors, mon ComboBox:
<ComboBox ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer}"
ItemTemplate="{StaticResource CustomerTemplate}" />
La partie importante de l'obtenir pour fonctionner est Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}"
(la partie où la valeur doit être x:Null, True).
- Votre solution fonctionne, mais j'ai des erreurs dans la fenêtre de Sortie.
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ComboBoxItem', AncestorLevel='1''. BindingExpression:Path=IsSelected; DataItem=null; target element is 'ContentPresenter' (Name=''); target property is 'NoTarget' (type 'Object')
- Je me souviens avoir vu ces trop d'erreurs. Mais je ne suis plus sur le projet (ou même dans la société), donc je ne peux pas le vérifier, désolé.
- La mention du Chemin de Liaison dans le DataTrigger est inutile. Comme le ComboBoxItem est sélectionné, un autre modèle sera appliqué pour le contrôle et la DataTrigger de liaison de ne plus être en mesure de trouver un ancêtre de type ComboBoxItem dans son élément de l'arbre. Ainsi, la comparaison avec la valeur null est toujours réussie. Cette méthode fonctionne parce que le Visuel de l'arbre de la ComboBoxItem est différent selon qu'il est sélectionné ou de l'afficher dans la fenêtre contextuelle.
Vous devez vous connecter pour publier un commentaire.
De la question avec l'aide de la DataTrigger/Liaison solution mentionnée ci-dessus sont de deux ordres. Le premier est que vous effectivement se retrouver avec une liaison avertissement que vous ne pouvez pas trouver la source par rapport pour l'élément sélectionné. Le plus gros problème, cependant, est que vous avez encombré de vos modèles de données et les a rendus propres à une zone de liste déroulante.
La solution que j'ai mieux comprendre le présent suit WPF conceptions en ce qu'il utilise un
DataTemplateSelector
sur laquelle vous pouvez spécifier les modèles distincts à l'aide de sonSelectedItemTemplate
etDropDownItemsTemplate
propriétés ainsi que "sélecteur" variantes pour les deux.J'ai également inclus une extension de balisage qui crée et retourne la classe ci-dessus pour plus de commodité dans le code XAML.
Et voici comment vous l'utilisez. Agréable, propre et clair, et vos modèles de rester "pure"
Vous pouvez également utiliser DataTemplateSelectors si vous préférez...
Ou mélanger et assortir! Ici, je suis en utilisant un modèle de l'élément sélectionné, mais un sélecteur de modèle pour les éléments de liste Déroulante.
En outre, si vous ne spécifiez pas un Modèle ou un TemplateSelector pour le ou les éléments de liste déroulante, tout simplement, il revient à l'ordinaire de la résolution des modèles de données de base sur les types de données, de nouveau, comme vous le souhaitez. Ainsi, par exemple, dans le cas ci-dessous, l'élément sélectionné est un modèle défini explicitement, mais la liste déroulante héritera selon le modèle de données s'applique pour le Type de données de l'objet dans le contexte de données.
Profitez-en!
return inDropDown
ci-dessus) utilise le C#6 ?. syntaxe donc, si vous ne l'utilisez pas VS 2015, il suffit de retirer le '?' et explicite de vérifier si les valeurs null avant d'appelerSelectTemplate
. J'ajouterai que pour le code.Solution Simple:
(Notez que l'élément qui est sélectionné et affiché dans la boîte et non pas la liste n'est pas à l'intérieur d'un
ComboBoxItem
donc sur la gâchette deNull
)Si vous voulez passer l'ensemble du modèle, vous pouvez le faire à l'aide de la gâchette, par exemple appliquer un
ContentTemplate
àContentControl
. Cela permet également de conserver un défautDataType
modèle basé sur la sélection si vous venez de changer le modèle de ce sélective cas, par exemple:Noter que cette méthode provoque la liaison des erreurs que la source n'est pas trouvé pour l'élément sélectionné. Pour une autre approche, voir MarqueIV réponse.
IsSelected
n'est pas les valeurs null et donc ne peut jamais être vraiment NUL. Vous n'avez pas besoinPath=IsSelected
, parce que le NUL de vérifier pour un environnantes ComboBoxItem est totalement suffisant.Artiom
s'approche? (Comme vous le mentionnezShortName
.)J'allais suggérer à l'aide de la combinaison d'un ItemTemplate pour le combo éléments, avec le paramètre de Texte comme le titre de la sélection, mais je vois que la zone de liste déroulante de ne pas respecter le Texte de paramètre.
J'ai traité avec quelque chose de similaire en remplaçant la zone de liste déroulante ControlTemplate. Voici la MSDN site web auprès d'un échantillon de .NET 4.0.
Dans ma solution, j'ai changer le ContentPresenter dans la zone de liste déroulante modèle de l'avoir à se lier à un Texte, avec ses ContentTemplate lié à un simple DataTemplate qui contient un TextBlock comme suit:
dans la ControlTemplate:
Avec ce lien, je suis en mesure de contrôler la liste déroulante de sélection d'affichage directement via le paramètre de Texte sur le contrôle (qui, je le lier à une valeur appropriée sur mon ViewModel).
J'ai utilisé approche suivante
Et le comportement
a travaillé comme un charme. N'aime pas assez bien Chargé cas ici, mais vous pouvez le réparer si vous voulez
Oui. Vous utilisez un Sélecteur de Modèle pour déterminer le modèle à lier au moment de l'exécution. Ainsi, si IsSelected = Faux alors Utiliser ce modèle, si IsSelected = True, l'utilisation de cette autre modèle.
De La Note:
Une fois que vous mettez en œuvre votre sélecteur de modèle, vous serez besoin de donner les modèles keynames.
En plus de ce que dit par H. B. réponse, la Liaison Erreur peut être évitée avec un Convertisseur. L'exemple suivant est basé à partir de la Solution éditée par l' L'OP lui-même.
L'idée est très simple: se lier à quelque chose qui existe toujours (
Control
) et de la vérifier à l'intérieur du convertisseur.La partie pertinente de la modification de XAML est le suivant. Veuillez noter que
Path=IsSelected
n'a jamais été vraiment nécessaire etComboBoxItem
est remplacé parControl
pour éviter les erreurs de liaison.Le C# Converter code est le suivant: