2009-08-13 9 views
21

Je tente d'écrire un projet d'apprentissage WPF simple qui crée un ensemble de boutons dans une fenêtre principale redimensionnable. Il doit y avoir un Button par entrée dans une collection, et le contenu de cette collection peut varier pendant l'exécution. Je veux que les boutons remplissent toute la fenêtre (par exemple, 1 bouton @ 100% de largeur, 2 boutons @ 50% de largeur, 3 boutons @ 33% de largeur, etc. tous à 100% de hauteur). Une version simplifiée de ce que j'ai écrit à ce jour est:Contrôles d'étirement pour remplir ItemsControl

<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:

alt text

Je suis incapable de faire les boutons Étirer pour adapter la largeur et mes tentatives pour utiliser un Grid au lieu de StackPanel étaient infructueuses. Puis, en tant qu'amélioration optionnelle, j'apprécierais des suggestions sur la façon de l'ajuster de sorte que s'il y a tellement de boutons qu'ils ne peuvent pas s'adapter correctement sur une ligne ou soient plus étroits qu'un seuil, ils s'enrouleront sur une nouvelle ligne (réduisant ainsi la hauteur des boutons si vous passez de 1 à 2 rangs).

Je voudrais souligner que je voudrais savoir comment faire le WPF way. Je me rends compte que je peux consommer des messages de redimensionnement de fenêtre et redimensionner les contrôles explicitement, et c'est ainsi que je l'aurais fait avec MFC ou WinForms, mais d'après ce que j'ai lu ce n'est pas comme ça.

Répondre

48

Remplacer le panneau de commande de l'élément avec un UniformGrid, cette taille que tous les enfants si tout se exactement:

<ItemsControl> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <UniformGrid Rows="1"/> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
</ItemsControl> 
+0

C'était exactement ce dont j'avais besoin pour mon objectif principal, merci. – Gregyski

+0

Grâce à la réponse de Nir, j'ai pu répondre au critère optionnel. Les détails sont dans la réponse que j'ai posté à cette question. Il a été recommandé sur Meta que je gère cette situation de cette façon. http://meta.stackexchange.com/questions/14306/my-improved-answer-based-on-anothers-accepted-answer-for-my-own-question – Gregyski

+0

Merci! C'est juste ce qui me manquait pour espacer les éléments et leur panneau uniformément dans une liste. –

0
<!-- 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; 
    } 
} 
+0

J'ai édité mon poste seulement 20 minutes avant que vous ayez répondu pour expliquer que je voulais éviter de définir explicitement la largeur. Je suis désolé j'aurais dû penser à inclure cette exigence au départ. La gestion explicite des dimensions comme celle-ci (et la gestion des messages de redimensionnement) peut être nécessaire pour mon besoin secondaire, si WrapPanel devait être utilisé. Merci. – Gregyski

2

Je suis en mesure de construire sur la réponse de Nir pour remplir mon critère facultatif permettant l'étirement géré par WPF avec plusieurs lignes.

Vous devez d'abord ê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 multiple methods for accomplishing this. J'ai choisi de gérer l'événement chargé pour le UniformGrid et de 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 derrière:

UniformGrid uniformgridButtons; 
private void UniformGrid_Loaded(object sender, RoutedEventArgs e) 
{ 
    uniformgridButtons = sender as UniformGrid; 
} 

Ensuite, la poignée SizeChanged événement et régler le paramètre lignes en fonction des critères que vous souhaitez peu importe.

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)); 
    } 
} 

Ainsi, 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:

alt text

(échantillon d'animation here)


Mise à jour 2009/08/28:

J'ajustais ma demande d'apprentissage afin que la ItemsControl était dans un DataTemplate dans un ResourceDictionary séparé. Toutefois, des événements tels que Loaded ne peuvent pas être gérés dans un fichier XAML ResourceDictionary externe car il ne contient pas de code-behind (généralement). Par conséquent, j'avais besoin de mettre en cache la référence au UniformGrid en utilisant une technique différente.

J'ai plutôt utilisé Alan Haigh's FindItemsPanel method (10th reply). Tout d'abord, je l'ai remplacé le ItemsControl avec:

<ContentPresenter x:Name="contentpresenterButtons" Content="{Binding obscolButtons}" /> 

Puis dans mon ResourceDictionary, je mets les ItemsControl dans le DataTemplate:

<DataTemplate DataType="{x:Type local:Buttons}"> 
    <ItemsControl ... 
</DataTemplate> 

Enfin, j'emmagasinés la référence au UniformGrid basé sur un modèle comme si:

Cela fonctionne exactement comme ma solution précédente mais sans nécessiter de gestionnaire.