¿Cómo puedo espaciar los elementos secundarios de un StackPanel?


Dado un StackPanel:

<StackPanel>
  <TextBox Height="30">Apple</TextBox>
  <TextBox Height="80">Banana</TextBox>
  <TextBox Height="120">Cherry</TextBox>
</StackPanel>

¿Cuál es la mejor manera de espaciar los elementos secundarios para que haya espacios de igual tamaño entre ellos, a pesar de que los elementos secundarios en sí son de diferentes tamaños? ¿Se puede hacer sin establecer propiedades en cada uno de los hijos individuales?

Author: Dave Clemmer, 2009-05-31

10 answers

Use Margin o Padding, aplicado al ámbito dentro del contenedor:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="0,10,0,0"/>
        </Style>
    </StackPanel.Resources> 
    <TextBox Text="Apple"/>
    <TextBox Text="Banana"/>
    <TextBox Text="Cherry"/>
</StackPanel>

EDITAR: En caso de que desee reutilizar el margen entre dos contenedores, puede convertir el valor del margen en un recurso en un ámbito externo, por ejemplo

<Window.Resources>
    <Thickness x:Key="tbMargin">0,10,0,0</Thickness>
</Window.Resources>

Y luego referirse a este valor en el ámbito interno

<StackPanel.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
    </Style>
</StackPanel.Resources>
 239
Author: Sergey Aldoukhov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-01 02:17:30

Otro buen enfoque se puede ver aquí: http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-items-in-stackpanel.aspx

Muestra cómo crear un comportamiento adjunto, para que una sintaxis como esta funcione:

<StackPanel local:MarginSetter.Margin="5">
   <TextBox Text="hello" />
   <Button Content="hello" />
   <Button Content="hello" />
</StackPanel>

Esta es la forma más fácil y rápida de establecer el margen a varios hijos de un panel, incluso si no son del mismo tipo. (Es decir, Botones, cuadros de texto, ComboBoxes, etc.)

 73
Author: Elad Katz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-15 00:48:43

Mejoré la respuesta de Elad Katz.

  • Agregue la propiedad LastItemMargin a MarginSetter para manejar especialmente el último elemento
  • Agregar espaciado propiedad adjunta con propiedades Verticales y Horizontales que agrega espaciado entre elementos en listas verticales y horizontales y elimina cualquier margen final al final de la lista

Código Fuente en gist.

Ejemplo:

<StackPanel Orientation="Horizontal" foo:Spacing.Horizontal="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<StackPanel Orientation="Vertical" foo:Spacing.Vertical="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<!-- Same as vertical example above -->
<StackPanel Orientation="Vertical" foo:MarginSetter.Margin="0 0 0 5" foo:MarginSetter.LastItemMargin="0">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>
 10
Author: angularsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-09 20:29:40

Lo que realmente quieres hacer es envolver todos los elementos secundarios. En este caso, debe utilizar un control de artículos y no recurrir a horribles propiedades adjuntas que terminarán teniendo un millón de por cada propiedad que desea estilo.

<ItemsControl>

    <!-- target the wrapper parent of the child with a style -->
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="Control">
            <Setter Property="Margin" Value="0 0 5 0"></Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>

    <!-- use a stack panel as the main container -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- put in your children -->
    <ItemsControl.Items>
        <Label>Auto Zoom Reset?</Label>
        <CheckBox x:Name="AutoResetZoom"/>
        <Button x:Name="ProceedButton" Click="ProceedButton_OnClick">Next</Button>
        <ComboBox SelectedItem="{Binding LogLevel }" ItemsSource="{Binding LogLevels}" />
    </ItemsControl.Items>
</ItemsControl>

introduzca la descripción de la imagen aquí

 6
Author: bradgonesurfing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-16 10:18:32

+1 para la respuesta de Sergey. Y si quieres aplicar eso a todos tus StackPanels puedes hacer esto:

<Style TargetType="{x:Type StackPanel}">
    <Style.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
        </Style>
    </Style.Resources>
</Style>

Pero ten cuidado: si defines un estilo como este en tu App.xaml (u otro diccionario que se fusiona en la Aplicación.Recursos) puede anular el estilo predeterminado del control. Para la mayoría de los controles sin aspecto como el stackpanel no es un problema, pero para los cuadros de texto, etc., puede tropezar con este problema, que afortunadamente tiene algunas soluciones.

 4
Author: Andre Luus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:35

Siguiendo la sugerencia de Sergey, puede definir y reutilizar un Estilo completo (con varios configuradores de propiedades, incluido Margin) en lugar de solo un objeto Thickness:

<Style x:Key="MyStyle" TargetType="SomeItemType">
  <Setter Property="Margin" Value="0,5,0,5" />
  ...
</Style>

...

  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="SomeItemType" BasedOn="{StaticResource MyStyle}" />
    </StackPanel.Resources>
  ...
  </StackPanel>

Tenga en cuenta que el truco aquí es el uso de la herencia de estilo para el estilo implícito, heredando del estilo en algún diccionario de recursos externo (probablemente fusionado del archivo XAML externo).

Nota lateral:

Al principio, ingenuamente traté de usar el estilo implícito para establecer la propiedad Style del control a ese recurso de Estilo externo (digamos definido con la clave "MyStyle"):

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="SomeItemType">
      <Setter Property="Style" Value={StaticResource MyStyle}" />
    </Style>
  </StackPanel.Resources>
</StackPanel>

Que causó que Visual Studio 2010 se cerrara inmediatamente con un ERROR DE FALLA CATASTRÓFICA (HRESULT: 0x8000FFFF (E_UNEXPECTED)), como se describe en https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#

 3
Author: George Birbilis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-11 10:15:45

Es posible que UniformGrid no esté disponible en Silverlight, pero alguien lo ha portado desde WPF. http://www.jeff.wilcox.name/2009/01/uniform-grid /

 2
Author: Jean Azzopardi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-31 18:22:27

Grid.Espacio de columnas, Grid.Espacio de filas, StackPanel.Spacing ahora están en la vista previa de UWP, todo permitirá completar mejor lo que se solicita aquí.

Estas propiedades actualmente solo están disponibles con el SDK de Windows 10 Fall Creators Update Insider, ¡pero deberían llegar a los bits finales!

 2
Author: Pedro Lamas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-06 15:17:59

Mi enfoque hereda StackPanel.

Uso:

<Controls:ItemSpacer Grid.Row="2" Orientation="Horizontal" Height="30" CellPadding="15,0">
    <Label>Test 1</Label>
    <Label>Test 2</Label>
    <Label>Test 3</Label>
</Controls:ItemSpacer>

Todo lo que se necesita es la siguiente clase corta:

using System.Windows;
using System.Windows.Controls;
using System;

namespace Controls
{
    public class ItemSpacer : StackPanel
    {
        public static DependencyProperty CellPaddingProperty = DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(ItemSpacer), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCellPaddingChanged));
        public Thickness CellPadding
        {
            get
            {
                return (Thickness)GetValue(CellPaddingProperty);
            }
            set
            {
                SetValue(CellPaddingProperty, value);
            }
        }
        private static void OnCellPaddingChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
        {
            ((ItemSpacer)Object).SetPadding();
        }

        private void SetPadding()
        {
            foreach (UIElement Element in Children)
            {
                (Element as FrameworkElement).Margin = this.CellPadding;
            }
        }

        public ItemSpacer()
        {
            this.LayoutUpdated += PART_Host_LayoutUpdated;
        }

        private void PART_Host_LayoutUpdated(object sender, System.EventArgs e)
        {
            this.SetPadding();
        }
    }
}
 1
Author: James M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-09 22:34:26

A veces es necesario establecer el relleno, no el margen para que el espacio entre los elementos sea menor que el predeterminado

 0
Author: Serov Danil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-25 13:41:01