Stretching contrôles pour remplir ItemsControl
-
13-09-2019 - |
Question
Je cherche à écrire un projet simple d'apprentissage WPF qui crée un ensemble de boutons dans une fenêtre principale redimensionnable. Il est l'un Button
par entrée dans une collection, et le contenu de cette collection peut varier au cours de l'exécution. Je veux les boutons pour remplir toute la fenêtre (par exemple une touche @ largeur de 100%, 2 touches @ largeur de 50%, 3 boutons @ largeur de 33%, etc., le tout à hauteur de 100%). Une version simplifiée de ce jour ce que j'ai écrit est:
<ItemsControl x:Name="itemscontrolButtons" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Tag="{Binding}">
<TextBlock Text="{Binding}" />
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
...
List<string> listButtonTexts = new List<string>() { "Button1", "Button2" };
...
itemscontrolButtons.DataContext = listButtonTexts;
Il en résulte ceci:
Je suis incapable de faire les boutons Étirer pour adapter la largeur et mes tentatives d'utiliser un Grid
au lieu de StackPanel
ont été vaines.
Alors, comme une amélioration facultative, je vous serais reconnaissant de suggestions sur la façon de le régler de telle sorte que s'il y a tellement de boutons qu'ils ne rentre pas correctement sur une ligne ou sont plus étroites que d'un seuil, il se terminera sur une nouvelle ligne ( la réduction de moitié de ce fait la hauteur des boutons si allant de 1 à 2 lignes).
Je voudrais souligner que je voudrais savoir comment faire le façon WPF . Je me rends compte que je peux consommer fenêtre redimensionne les messages et redimensionnez les contrôles explicitement, et comment je l'aurais fait avec MFC ou WinForms, mais de ce que j'ai lu ce n'est pas comment devrait se faire de telles choses avec WPF.
La solution
Remplacer le panneau de commande de l'élément avec un UniformGrid, cette taille que tous les enfants, donc tout correspond exactement à:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Autres conseils
Je suis en mesure de construire sur la réponse de Nir pour remplir mon critère option permettant WPF gérés étirement avec plusieurs lignes.
D'abord, vous devez être en mesure de modifier les propriétés du modèle UniformGrid . Pour ce faire, vous devez stocker une référence. Il y a plusieurs méthodes pour accomplir cette . J'ai choisi de gérer les Loaded événement pour UniformGrid et stocker une référence à ce moment-là.
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Loaded="UniformGrid_Loaded" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Et dans le code sous-jacent:
UniformGrid uniformgridButtons;
private void UniformGrid_Loaded(object sender, RoutedEventArgs e)
{
uniformgridButtons = sender as UniformGrid;
}
Ensuite, gérer les SizeChanged événement et régler le paramètre lignes selon tout critère que vous souhaitez.
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
if ((uniformgridButtons != null) && (this.Width > 0))
{
// Set row count according to your requirements
uniformgridButtons.Rows = (int)(1 + ((this.MinWidth * iButtonCount) / this.Width));
}
}
Alors cela permet WPF de gérer l'étirement comme dans la réponse de Nir, mais vous permet d'ajuster explicitement le nombre de lignes. Le code ci-dessus donne ce résultat:
Mise à jour 2009/08/28:
J'ajustais ma demande d'apprentissage afin que le ItemsControl
était dans un DataTemplate
dans un ResourceDictionary
séparé. Cependant, des événements tels que Loaded
ne peuvent pas être traitées dans un fichier XAML ResourceDictionary
externe, car il n'a pas de code-behind (en général). Par conséquent, je avais besoin de mettre en cache la référence au UniformGrid
en utilisant une technique différente.
au lieu utilisé la méthode de FindItemsPanel
d'Alan Haigh (10 réponses) . Tout d'abord, je l'ai remplacé le ItemsControl
avec:
<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" />
Alors dans mon ResourceDictionary
, je mets le ItemsControl
dans le DataTemplate
:
<DataTemplate DataType="{x:Type local:Buttons}">
<ItemsControl ...
</DataTemplate>
Enfin, j'emmagasinés la référence au UniformGrid
comme si basé sur un modèle:
private void Window_Loaded(object sender, RoutedEventArgs e) {
uniformgridButtons = FindItemsPanel<UniformGrid>(contentpresenterButtons);
// Also call the code in Window_SizeChanged which I put in another method
}
Cela fonctionne exactement la même chose que ma solution précédente, mais sans nécessiter un gestionnaire d'événements dans le ResourceDictionary
.
<!-- width must be explicitly set for this example -->
<StackPanel
Name="MyStack"
Orientation="Horizontal"
Width="250"
Load="Window_Loaded">
<Button/>
<Button/>
<Button/>
</StackPanel>
public void Window_Loaded(object sender, RoutedEventArgs e)
{
UIElementCollection elements = MyStack.Children;
int count = elements.Count;
foreach (UIElement element in elements)
{
if (element is Button)
((Button)element).Width = MyStack.Width / count;
}
}