¿Cómo hacer que los hijos de StackPanel llenen el espacio máximo hacia abajo?

356

Simplemente quiero un texto fluido a la izquierda y un cuadro de ayuda a la derecha.

El cuadro de ayuda debe extenderse hasta el final.

Si sacas el exterior StackPaneldebajo, funciona muy bien.

Pero por razones de diseño (estoy insertando UserControls dinámicamente) necesito tener el ajuste StackPanel.

¿Cómo consigo GroupBoxque se extienda hasta la parte inferior de la StackPanel, como puede ver que he intentado:

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

Responder:

Gracias Mark, usando en DockPanellugar de StackPanelaclarado. En general, me encuentro usando DockPanelmás y más ahora para el diseño de WPF, aquí está el XAML fijo:

<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
fuente
Se corrigió el formato - no le gusta ir directamente de una lista al código
Greg
1
¿Puedes hacer que un GroupBox se estire de esa manera por sí solo? Si es así, comience a agregar sus elementos principales uno por uno hasta que descubra cuál está rompiendo el diseño.
Drew Noakes
RoBorg: es bueno saberlo, eso me dejó perplejo, gracias
Edward Tanguay
1
Gracias. ¡Usando su respuesta pude usar 2 DockPanels anidados para resolver mi problema muy similar!
Yablargo

Respuestas:

344

Parece que quiere un lugar StackPaneldonde el elemento final usa todo el espacio restante. Pero, ¿por qué no usar a DockPanel? Decora los otros elementos en el DockPanelcon DockPanel.Dock="Top", y luego tu control de ayuda puede llenar el espacio 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>

Si está en una plataforma sin DockPaneldisponibilidad (por ejemplo, WindowsStore), puede crear el mismo efecto con una cuadrícula. Aquí está el ejemplo anterior realizado utilizando cuadrículas en su lugar:

<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
fuente
18
¡Brillante! Pasé la última hora tratando de descubrir cómo hacer que StackPanel haga esto. De ahora en adelante, buscaré aquí primero mi información de WPF (y otra).
paxdiablo
77
No puedo creer cuánto tiempo he pasado intentando que StackPanels haga lo que quería. ¡Gracias por compartir! DockPanels es lo que siempre quise.
danglund
Parece que no hay panel de acoplamiento para tabletas. telerik.com/forums/following-blog-post-and-comparison
JP Hellemons
1
No hay panel de acoplamiento para aplicaciones de la Tienda Windows.
Teoman shipahi
¿Ahora se trata de una aplicación universal y las aplicaciones universales aún no son compatibles con DockPanel?
yonexbat
105

La razón por la que esto sucede es porque el panel de pila mide cada elemento secundario con infinito positivo como la restricción para el eje en el que está apilando elementos. Los controles secundarios tienen que devolver qué tan grandes quieren ser (el infinito positivo no es un retorno válido de MeasureOverride en ninguno de los ejes) para que devuelvan el tamaño más pequeño donde todo encajará. No tienen forma de saber cuánto espacio realmente tienen que llenar.

Si su vista no necesita tener una función de desplazamiento y la respuesta anterior no satisface sus necesidades, sugeriría implementar su propio panel. Probablemente pueda derivar directamente de StackPanel y luego todo lo que tendrá que hacer es cambiar el método ArrangeOverride para que divida el espacio restante entre sus elementos secundarios (dándoles a cada uno la misma cantidad de espacio extra). Los elementos deberían funcionar bien si se les da más espacio del que querían, pero si les das menos, comenzarás a ver fallas.

Si quieres poder desplazarte todo, me temo que las cosas serán un poco más difíciles, porque ScrollViewer te brinda una cantidad infinita de espacio para trabajar que te colocará en la misma posición que los elementos secundarios. originalmente. En esta situación, es posible que desee crear una nueva propiedad en su nuevo panel que le permita especificar el tamaño de la ventana gráfica, debería poder vincular esto al tamaño de ScrollViewer. Lo ideal sería implementar IScrollInfo , pero eso comenzará a complicarse si va a implementar todo correctamente.

Caleb Vear
fuente
+1, le daría más, pero solo 1 está permitido, su primer párrafo ha señalado lo que muchas páginas de Microsoft no han logrado, es decir, por qué el infinito puede ocurrir como una altura / ancho y el hecho de que no puede confiar en regresar disponible Tamaño desde MeasureOverride .
Aidan
Un StackPanel dentro de un Grid resuelve su necesidad bastante común con gran facilidad. El bit inferior podría colocarse dentro de un ScrollViewer, si es necesario. He estado haciendo WPF desde 2006 y solo una vez he necesitado hacer un panel personalizado. No creo que sea una buena idea fomentar la complejidad adicional.
Chris Bordeman
@ChrisBordeman No estoy seguro de entender cómo el panel de la pila dentro de la cuadrícula resuelve el problema. La idea es tener uno o más elementos secundarios en el panel de la pila estirados para llenar el espacio disponible. Poner el panel de la pila dentro de una cuadrícula no hace que lo haga, ¿verdad?
Caleb Vear
61

Un método alternativo es usar una cuadrícula con una columna yn filas. Establezca todas las alturas de las filas en Auto, y la altura de la fila más inferior en 1*.

Prefiero este método porque he descubierto que las cuadrículas tienen un mejor rendimiento de diseño que DockPanels, StackPanels y WrapPanels. Pero a menos que los esté utilizando en un ItemTemplate (donde se realiza el diseño para una gran cantidad de elementos), probablemente nunca lo notará.

rcabr
fuente
1
Para mí la mejor solución. con esto es posible definir más de una fila en crecimiento
niyou
18

Puede usar SpicyTaco.AutoGrid , una versión 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>

El primer botón se llenará.

Puede instalarlo a través de NuGet:

Install-Package SpicyTaco.AutoGrid

Recomiendo echar un vistazo a SpicyTaco.AutoGrid . Es muy útil para las formas en lugar de WPF DockPanel, StackPanely Gridya resolver un problema con el estiramiento muy fácil y con gracia. Solo mira el archivo Léame en GitHub.

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

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

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