Вопрос

Учитывая StackPanel:

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

Как лучше всего расположить дочерние элементы так, чтобы между ними были одинаковые промежутки, даже если сами дочерние элементы имеют разные размеры?Можно ли это сделать, не устанавливая свойства для каждого отдельного дочернего элемента?

Это было полезно?

Решение

Используйте Margin или Padding, применяемые к области внутри контейнера:

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

РЕДАКТИРОВАТЬ:Если вы хотите повторно использовать поле между двумя контейнерами, вы можете преобразовать значение поля в ресурс во внешней области, например.

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

а затем обратитесь к этому значению во внутренней области видимости

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

Другие советы

Еще один хороший подход можно увидеть здесь:http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-items-in-stackpanel.aspx

Он показывает, как создать прикрепленное поведение, чтобы работал такой синтаксис:

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

Это самый простой и быстрый способ установить поле для нескольких дочерних элементов панели, даже если они не одного типа.(т.е.Кнопки, текстовые поля, поля со списком и т. д.)

я улучшился Ответ Элада Каца.

  • Добавьте свойство LastItemMargin в MarginSetter для специальной обработки последнего элемента.
  • Добавьте присоединенное свойство «Интервал» со свойствами «Вертикально» и «Горизонтально», которое добавляет расстояние между элементами в вертикальных и горизонтальных списках и устраняет любые конечные поля в конце списка.

Исходный код в сути.

Пример:

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

Что вам действительно нужно сделать, так это обернуть все дочерние элементы.В этом случае вам следует использовать элемент управления элементами и не прибегать к ужасным присоединенным свойствам, которых в конечном итоге у вас будет миллион для каждого свойства, которое вы хотите стилизовать.

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

enter image description here

+1 за ответ Сергея.И если вы хотите применить это ко всем своим StackPanels, вы можете сделать это:

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

Но будьте осторожны: если вы определите такой стиль в своем App.xaml (или другом словаре, объединенном с Application.Resources), он может переопределить стиль элемента управления по умолчанию.Для в основном невыглядящих элементов управления, таких как панель стека, это не проблема, но для текстовых полей и т. д. вы можете наткнуться на Эта проблема, который, к счастью, имеет обходные пути.

Следуя предложению Сергея, вы можете определить и повторно использовать целый стиль (с различными настройками свойств, включая Margin), а не только объект 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>

Обратите внимание, что хитрость здесь заключается в использовании наследования стиля для неявного стиля, наследуемого от стиля в каком-то внешнем (вероятно, объединенном из внешнего файла XAML) словаре ресурсов.

Примечание:

Сначала я наивно пытался использовать неявный стиль, чтобы установить свойство Style элемента управления для этого внешнего ресурса Style (скажем, определенного с помощью ключа «MyStyle»):

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

что привело к немедленному завершению работы Visual Studio 2010 с ошибкой CATASTROPHIC FAILURE (HRESULT:0x8000FFFF (E_UNEXPECTED)), как описано в https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastropic-failure-when-a-style-tries-to-set-style-property#

Grid.ColumnSpacing, Grid.RowSpacing, StackPanel.Spacing сейчас находятся в предварительной версии UWP, все это позволит лучше выполнить то, что здесь требуется.

Эти свойства в настоящее время доступны только в составе Windows 10 Fall Creators Update Insider SDK, но они должны дойти до финальной версии!

UniformGrid может быть недоступен в Silverlight, но кто-то перенес его из WPF. http://www.jeff.wilcox.name/2009/01/uniform-grid/

Мой подход наследует StackPanel.

Использование:

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

Все, что нужно, это следующий короткий класс:

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

иногда вам нужно установить Padding, а не Margin, чтобы пространство между элементами было меньше, чем по умолчанию.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top