Comment faire en sorte que les enfants de StackPanel remplissent l'espace maximum vers le bas?

356

Je veux simplement un texte fluide à gauche et une boîte d'aide à droite.

La boîte d'aide doit s'étendre jusqu'en bas.

Si vous sortez l'extérieur StackPanelci-dessous, cela fonctionne très bien.

Mais pour des raisons de mise en page (j'insère dynamiquement les UserControls), j'ai besoin d'avoir le wrapping StackPanel.

Comment puis-je obtenir le GroupBoxprolongement vers le bas de la StackPanel, comme vous pouvez le voir, j'ai essayé:

  • VerticalAlignment="Stretch"
  • VerticalContentAlignment="Stretch"
  • Height="Auto"

XAML:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600">
    <StackPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                Background="Beige" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" />
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </StackPanel>
</Window>

Réponse:

Merci Mark, en utilisant DockPanelau lieu de l' StackPaneléclaircir. En général, je me retrouve à utiliser de DockPanelplus en plus maintenant pour la mise en page WPF, voici le XAML fixe:

<Window x:Class="TestDynamic033.Test3"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Test3" Height="300" Width="600" MinWidth="500" MinHeight="200">
    <DockPanel 
        VerticalAlignment="Stretch" 
        Height="Auto">

        <DockPanel 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch" 
            Height="Auto" 
            MinWidth="400"
            Margin="10">

            <GroupBox 
                DockPanel.Dock="Right" 
                Header="Help" 
                Width="100" 
                VerticalAlignment="Stretch" 
                VerticalContentAlignment="Stretch" 
                Height="Auto">
                <Border CornerRadius="3" Background="Beige">
                    <TextBlock Text="This is the help that is available on the news screen." TextWrapping="Wrap" 

                Padding="5"/>
                </Border>
            </GroupBox>

            <StackPanel DockPanel.Dock="Left" Margin="10" Width="Auto" HorizontalAlignment="Stretch">
                <TextBlock Text="Here is the news that should wrap around." TextWrapping="Wrap"/>
            </StackPanel>

        </DockPanel>
    </DockPanel>
</Window>
Edward Tanguay
la source
Correction du formatage - il n'aime pas passer directement d'une liste au code
Greg
1
Pouvez-vous faire un GroupBox étirer de cette façon tout seul? Si c'est le cas, commencez à ajouter vos éléments parents un par un jusqu'à ce que vous découvriez lequel casse la disposition.
Drew Noakes
RoBorg: bon à savoir, cela m'a laissé perplexe, merci
Edward Tanguay
1
Merci. En utilisant votre réponse, j'ai pu utiliser 2 DockPanels imbriqués pour résoudre mon problème très similaire!
Yablargo

Réponses:

344

Il semble que vous souhaitiez un StackPanelendroit où l'élément final utilise tout l'espace restant. Mais pourquoi ne pas utiliser un DockPanel? Décorez les autres éléments du DockPanelavec DockPanel.Dock="Top", puis votre contrôle d'aide peut remplir l'espace restant.

XAML:

<DockPanel Width="200" Height="200" Background="PowderBlue">
    <TextBlock DockPanel.Dock="Top">Something</TextBlock>
    <TextBlock DockPanel.Dock="Top">Something else</TextBlock>
    <DockPanel
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Stretch" 
        Height="Auto" 
        Margin="10">

      <GroupBox 
        DockPanel.Dock="Right" 
        Header="Help" 
        Width="100" 
        Background="Beige" 
        VerticalAlignment="Stretch" 
        VerticalContentAlignment="Stretch" 
        Height="Auto">
        <TextBlock Text="This is the help that is available on the news screen." 
                   TextWrapping="Wrap" />
     </GroupBox>

      <StackPanel DockPanel.Dock="Left" Margin="10" 
           Width="Auto" HorizontalAlignment="Stretch">
          <TextBlock Text="Here is the news that should wrap around." 
                     TextWrapping="Wrap"/>
      </StackPanel>
    </DockPanel>
</DockPanel>

Si vous êtes sur une plate-forme non DockPaneldisponible (par exemple WindowsStore), vous pouvez créer le même effet avec une grille. Voici l'exemple ci-dessus accompli à l'aide de grilles à la place:

<Grid Width="200" Height="200" Background="PowderBlue">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <StackPanel Grid.Row="0">
        <TextBlock>Something</TextBlock>
        <TextBlock>Something else</TextBlock>
    </StackPanel>
    <Grid Height="Auto" Grid.Row="1" Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <GroupBox
            Width="100"
            Height="Auto"
            Grid.Column="1"
            Background="Beige"
            Header="Help">
            <TextBlock Text="This is the help that is available on the news screen." 
              TextWrapping="Wrap"/>
        </GroupBox>
        <StackPanel Width="Auto" Margin="10" DockPanel.Dock="Left">
            <TextBlock Text="Here is the news that should wrap around." 
              TextWrapping="Wrap"/>
        </StackPanel>
    </Grid>
</Grid>
Mark Heath
la source
18
Brillant! J'ai passé la dernière heure à essayer de comprendre comment obtenir StackPanel pour ce faire. À partir de maintenant, je vais d'abord chercher ici mes informations WPF (et autres).
paxdiablo
7
Je ne peux pas croire combien de temps j'ai passé à essayer de faire en sorte que StackPanels fasse ce que je voulais. Merci d'avoir partagé! Les DockPanels sont ce que je voulais depuis le début.
danglund
Il n'y a pas de dock pour les tablettes semble-t-il. telerik.com/forums/following-blog-post-and-comparison
JP Hellemons
1
Pas de panneau d'ancrage pour les applications du Windows Store.
Teoman shipahi
Maintenant, tout tourne autour de l'application universelle et les applications universelles ne prennent pas encore en charge DockPanel?
yonexbat
105

La raison en est que le panneau de pile mesure chaque élément enfant avec une infinité positive comme contrainte pour l'axe sur lequel il empile les éléments. Les contrôles enfants doivent renvoyer la taille qu'ils souhaitent avoir (l'infini positif n'est pas un retour valide du MeasureOverride dans l'un ou l'autre axe) afin qu'ils retournent la plus petite taille où tout ira. Ils n'ont aucun moyen de savoir combien d'espace ils doivent vraiment remplir.

Si votre vue n'a pas besoin d'avoir une fonction de défilement et que la réponse ci-dessus ne correspond pas à vos besoins, je vous suggère d'implémenter votre propre panneau. Vous pouvez probablement dériver directement de StackPanel, puis tout ce que vous aurez à faire est de modifier la méthode ArrangeOverride afin qu'elle divise l'espace restant entre ses éléments enfants (en leur donnant chacun la même quantité d'espace supplémentaire). Les éléments devraient s'afficher correctement s'ils disposent de plus d'espace qu'ils ne le souhaitaient, mais si vous leur en donnez moins, vous commencerez à voir des problèmes.

Si vous voulez pouvoir faire défiler le tout, je crains que les choses soient un peu plus difficiles, car le ScrollViewer vous donne une quantité infinie d'espace de travail avec laquelle vous placerez dans la même position que les éléments enfants. initialement. Dans cette situation, vous souhaiterez peut-être créer une nouvelle propriété sur votre nouveau panneau qui vous permettra de spécifier la taille de la fenêtre, vous devriez pouvoir la lier à la taille de ScrollViewer. Idéalement, vous implémenteriez IScrollInfo , mais cela commence à se compliquer si vous allez l'implémenter correctement.

Caleb Vear
la source
+1, je vous donnerais plus mais seulement 1 est autorisé, votre premier paragraphe a souligné ce que de nombreuses pages Microsoft ont échoué, à savoir pourquoi l'infini peut se produire en tant que hauteur / largeur et le fait que vous ne pouvez pas compter sur le retour de la taille disponible de MeasureOverride .
Aidan
Un StackPanel à l'intérieur d'une grille résout son besoin plutôt commun avec une grande facilité. Le bit inférieur peut être placé dans un ScrollViewer, si nécessaire. Je fais WPF depuis 2006 et je n'ai eu besoin qu'une seule fois de faire un panneau personnalisé. Je ne pense pas que ce soit une bonne idée d'encourager une complexité supplémentaire.
Chris Bordeman
@ChrisBordeman Je ne suis pas sûr de comprendre comment le panneau de pile à l'intérieur de la grille résout le problème. L'idée est d'avoir un ou plusieurs éléments enfants dans l'étirement du panneau de pile pour remplir l'espace disponible. Placer le panneau de pile à l'intérieur d'une grille ne le fait pas faire ça?
Caleb Vear le
61

Une autre méthode consiste à utiliser une grille avec une colonne et n lignes. Définissez toutes les hauteurs de lignes sur Autoet la hauteur de ligne la plus basse sur 1*.

Je préfère cette méthode car j'ai trouvé que les grilles ont de meilleures performances de mise en page que les DockPanels, StackPanels et WrapPanels. Mais à moins que vous ne les utilisiez dans un ItemTemplate (où la mise en page est effectuée pour un grand nombre d'éléments), vous ne le remarquerez probablement jamais.

rcabr
la source
1
pour moi la meilleure solution. avec cela, il est possible de définir plus d'une rangée croissante
niyou
18

Vous pouvez utiliser SpicyTaco.AutoGrid - une version modifiée de StackPanel:

<st:StackPanel Orientation="Horizontal" MarginBetweenChildren="10" Margin="10">
   <Button Content="Info" HorizontalAlignment="Left" st:StackPanel.Fill="Fill"/>
   <Button Content="Cancel"/>
   <Button Content="Save"/>
</st:StackPanel>

Le premier bouton sera rempli.

Vous pouvez l'installer via NuGet:

Install-Package SpicyTaco.AutoGrid

Je recommande de jeter un œil à SpicyTaco.AutoGrid . Il est très utile pour les formes en WPF au lieu de DockPanel, StackPanelet Gridet résoudre le problème avec des étirements très facile et avec élégance. Regardez simplement le fichier Lisez-moi sur GitHub.

<st:AutoGrid Columns="160,*" ChildMargin="3">
    <Label Content="Name:"/>
    <TextBox/>

    <Label Content="E-Mail:"/>
    <TextBox/>

    <Label Content="Comment:"/>
    <TextBox/>
</st:AutoGrid>
Dvor_nik
la source