Como fazer com que os filhos do StackPanel preencham o espaço máximo para baixo?

356

Eu simplesmente quero texto corrido à esquerda e uma caixa de ajuda à direita.

A caixa de ajuda deve se estender até o fim.

Se você tirar o exterior StackPanelabaixo, ele funciona muito bem.

Mas, por razões de layout (estou inserindo UserControls dinamicamente), preciso ter o empacotamento StackPanel.

Como faço GroupBoxpara estender até a parte inferior do StackPanel, como você pode ver, eu tentei:

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

Responda:

Obrigado Mark, usando em DockPanelvez de StackPanelesclarecer. Em geral, eu me vejo usando DockPanelcada vez mais agora o layout do WPF, aqui está o XAML fixo:

<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
fonte
Fixa a formatação - ele não gosta de ir direto a partir de uma lista de código
Greg
11
Você pode fazer um GroupBox esticar dessa maneira por conta própria? Nesse caso, comece a adicionar os elementos pai um a um até descobrir qual deles está quebrando o layout.
Drew Noakes
RoBorg: bom saber, que tinha me perplexo, graças
Edward Tanguay
11
Obrigado. Usando sua resposta, eu pude usar 2 DockPanels aninhados para resolver meu problema muito semelhante!
Yablargo 28/02

Respostas:

344

Parece que você deseja um local StackPanelonde o elemento final consome todo o espaço restante. Mas por que não usar um DockPanel? Decore os outros elementos DockPanelcom DockPanel.Dock="Top", e seu controle de ajuda poderá preencher o espaço restante.

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>

Se você estiver em uma plataforma sem DockPaneldisponibilidade (por exemplo, WindowsStore), poderá criar o mesmo efeito com uma grade. Aqui está o exemplo acima realizado usando grades:

<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
fonte
18
Brilhante! Passei a última hora tentando descobrir como fazer o StackPanel fazer isso. De agora em diante, procurarei aqui primeiro minhas informações sobre o WPF (e outras).
precisa
7
Não acredito quanto tempo passei tentando convencer o StackPanels a fazer o que eu queria. Obrigado por compartilhar! Os DockPanels são o que eu sempre quis.
Danglund 6/09/12
Parece que não há painel de encaixe para tablets. telerik.com/forums/following-blog-post-and-comparison
JP Hellemons
11
Nenhum painel de encaixe para aplicativos da Windows Store.
Teoman shipahi
Agora, é tudo sobre aplicativo universal e aplicativos universais ainda não suportam o DockPanel?
Yonexbat
105

A razão pela qual isso está acontecendo é porque o painel de pilha mede cada elemento filho com infinito positivo como a restrição para o eixo no qual está empilhando elementos. Os controles filho precisam retornar o tamanho que desejam (o infinito positivo não é um retorno válido do MeasureOverride nos dois eixos) para que eles retornem o menor tamanho em que tudo caiba. Eles não têm como saber quanto espaço realmente precisam preencher.

Se sua visualização não precisar ter um recurso de rolagem e a resposta acima não atender às suas necessidades, sugiro que implemente seu próprio painel. Provavelmente você pode derivar diretamente do StackPanel e, em seguida, tudo o que você precisa fazer é alterar o ArrangeOverride método para que ele divida o espaço restante entre seus elementos filhos (dando a cada um a mesma quantidade de espaço extra). Os elementos devem ficar bem se receberem mais espaço do que desejavam, mas se você der menos, começará a ver falhas.

Se você quiser rolar a coisa toda, receio que as coisas sejam um pouco mais difíceis, porque o ScrollViewer oferece uma quantidade infinita de espaço para trabalhar, o que o colocará na mesma posição que os elementos filhos. originalmente. Nessa situação, convém criar uma nova propriedade em seu novo painel, que permita especificar o tamanho da porta de visualização; você poderá vincular isso ao tamanho do ScrollViewer. Idealmente, você implementaria o IScrollInfo , mas isso começará a ficar complicado se você implementar tudo corretamente.

Caleb Vear
fonte
+1, eu daria a você mais, mas apenas 1 é permitido; seu primeiro parágrafo indicou o que várias páginas da Microsoft falharam, ou seja, por que o infinito pode ocorrer como uma altura / largura e o fato de que você não pode confiar em retornar o availableSize do MeasureOverride .
22412 Aidan
Um StackPanel dentro de uma grade resolve sua necessidade bastante comum com grande facilidade. O bit inferior pode ser colocado dentro de um ScrollViewer, se necessário. Trabalho no WPF desde 2006 e só precisei fazer um painel personalizado uma vez. Não acho uma boa ideia incentivar uma complexidade extra.
Chris Bordeman
@ChrisBordeman Não sei ao certo como o painel da pilha dentro da grade resolve o problema. A idéia é ter um ou mais elementos filhos no painel da pilha estendidos para preencher o espaço disponível. Colocar o painel da pilha dentro de uma grade não faz isso?
Caleb Vear 15/01
61

Um método alternativo é usar uma grade com uma coluna e n linhas. Defina todas as alturas das linhas como Autoe a altura mais inferior da linha como 1*.

Prefiro esse método porque descobri que o Grids tem melhor desempenho de layout que o DockPanels, StackPanels e WrapPanels. Mas, a menos que você os esteja usando em um ItemTemplate (onde o layout está sendo executado para um grande número de itens), você provavelmente nunca perceberá.

rcabr
fonte
11
para mim a melhor solução. com isso, é possível definir mais de uma linha crescente
niyou
18

Você pode usar o SpicyTaco.AutoGrid - uma versão modificada 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>

O primeiro botão será preenchido.

Você pode instalá-lo via NuGet:

Install-Package SpicyTaco.AutoGrid

Eu recomendo dar uma olhada no SpicyTaco.AutoGrid . É muito útil para formulários em WPF em vez de DockPanel, StackPanele Gride resolver o problema com alongamento muito fácil e graciosamente. Basta ler o leia-me no GitHub.

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

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

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