Je sais comment le faire dans le code, mais cela peut-il être fait en XAML?
Window1.xaml:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox Name="ComboBox1" HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBoxItem>ComboBoxItem1</ComboBoxItem>
<ComboBoxItem>ComboBoxItem2</ComboBoxItem>
</ComboBox>
</Grid>
</Window>
Window1.xaml.cs:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
double width = 0;
foreach (ComboBoxItem item in ComboBox1.Items)
{
item.Measure(new Size(
double.PositiveInfinity, double.PositiveInfinity));
if (item.DesiredSize.Width > width)
width = item.DesiredSize.Width;
}
ComboBox1.Measure(new Size(
double.PositiveInfinity, double.PositiveInfinity));
ComboBox1.Width = ComboBox1.DesiredSize.Width + width;
}
}
}
Réponses:
Cela ne peut pas être en XAML sans:
La raison en est que les modèles de contrôle ComboBox par défaut que j'ai rencontrés (Aero, Luna, etc.) imbriquent tous le ItemsPresenter dans une fenêtre contextuelle. Cela signifie que la mise en page de ces éléments est différée jusqu'à ce qu'ils soient réellement rendus visibles.
Un moyen simple de tester ceci est de modifier le ControlTemplate par défaut pour lier la MinWidth du conteneur le plus extérieur (c'est une Grid pour Aero et Luna) à la ActualWidth de PART_Popup. Vous pourrez faire en sorte que la zone de liste déroulante synchronise automatiquement sa largeur lorsque vous cliquez sur le bouton de dépôt, mais pas avant.
Donc, à moins que vous ne puissiez forcer une opération Mesure dans le système de mise en page (ce que vous pouvez faire en ajoutant un deuxième contrôle), je ne pense pas que cela puisse être fait.
Comme toujours, je suis ouvert à une solution courte et élégante - mais dans ce cas, les hacks code-behind ou dual-control / ControlTemplate sont les seules solutions que j'ai vues.
la source
Vous ne pouvez pas le faire directement dans Xaml mais vous pouvez utiliser ce comportement attaché. (La largeur sera visible dans le concepteur)
ComboBoxWidthFromItemsProperty de comportement attaché
Ce qu'il fait, c'est qu'il appelle une méthode d'extension pour ComboBox appelée SetWidthFromItems qui (de manière invisible) se développe et se réduit, puis calcule la largeur en fonction des ComboBoxItems générés. (IExpandCollapseProvider nécessite une référence à UIAutomationProvider.dll)
Puis méthode d'extension SetWidthFromItems
Cette méthode d'extension permet également d'appeler
dans le code derrière (par exemple dans l'événement ComboBox.Loaded)
la source
SetWidthFromItems
asynchrone en utilisant une action / un délégué et un BeginInvoke avec une priorité Idle (comme cela est fait dans l'événement Loaded). De cette façon, aucune mesure ne sera effectuée tant que la pompe de messagerie n'est pas vide, et par conséquent, aucun entrelacement de message ne se produiradouble comboBoxWidth = 19;
dans votre code est-il lié àSystemParameters.VerticalScrollBarWidth
?Ouais, celui-ci est un peu méchant.
Ce que j'ai fait dans le passé, c'est d'ajouter dans le ControlTemplate une zone de liste masquée (avec ses itemscontainerpanel définis sur une grille) montrant chaque élément en même temps mais avec leur visibilité définie sur hidden.
Je serais ravi d'entendre parler de meilleures idées qui ne reposent pas sur un horrible code-behind ou que votre vue doit comprendre qu'elle doit utiliser un contrôle différent pour fournir la largeur nécessaire pour prendre en charge les visuels (beurk!).
la source
Sur la base des autres réponses ci-dessus, voici ma version:
HorizontalAlignment = "Left" arrête les contrôles en utilisant toute la largeur du contrôle conteneur. Height = "0" masque le contrôle des éléments.
Margin = "15,0" permet d'ajouter du chrome autour des éléments de la boîte combo (pas agnostique du chrome, j'en ai peur).
la source
Je me suis retrouvé avec une solution «assez bonne» à ce problème étant de faire en sorte que la zone de liste déroulante ne rétrécisse jamais en dessous de la plus grande taille qu'elle contenait, similaire à l'ancien WinForms AutoSizeMode = GrowOnly.
La façon dont je l'ai fait était avec un convertisseur de valeur personnalisé:
Ensuite, je configure la zone de liste déroulante en XAML comme suit:
Notez qu'avec cela, vous avez besoin d'une instance distincte du GrowConverter pour chaque zone de liste déroulante, à moins bien sûr que vous ne souhaitiez qu'un ensemble d'entre eux soit dimensionné ensemble, similaire à la fonctionnalité SharedSizeScope de la grille.
la source
Une suite à la réponse de Maleak: j'ai tellement aimé cette implémentation que j'ai écrit un véritable Behavior pour cela. Évidemment, vous aurez besoin du SDK Blend pour pouvoir référencer System.Windows.Interactivity.
XAML:
Code:
la source
provider.Expand()
jette unElementNotEnabledException
. Lorsque le ComboBox n'est pas activé, en raison d'un parent étant désactivé, il n'est même pas possible d'activer temporairement le ComboBox jusqu'à ce que la mesure soit terminée.Placez une liste contenant le même contenu derrière la boîte de dépôt. Ensuite, appliquez une hauteur correcte avec une liaison comme celle-ci:
la source
Dans mon cas, un moyen beaucoup plus simple semblait faire l'affaire, je viens d'utiliser un stackPanel supplémentaire pour envelopper la combobox.
(travaillé en studio visuel 2008)
la source
Une solution alternative à la réponse principale consiste à mesurer le Popup lui-même plutôt que de mesurer tous les éléments. Donnant une
SetWidthFromItems()
mise en œuvre un peu plus simple :fonctionne également sur les handicapés
ComboBox
.la source
Je cherchais moi-même la réponse, quand je suis tombé sur la
UpdateLayout()
méthode que chacunUIElement
a.C'est très simple maintenant, heureusement!
Appelez simplement
ComboBox1.Updatelayout();
après avoir défini ou modifié le fichierItemSource
.la source
L'approche d'Alun Harford, en pratique:
la source
Cela permet de conserver la largeur de l'élément le plus large, mais seulement après avoir ouvert la zone de liste déroulante une fois.
la source