Как я могу выделить дочерние элементы StackPanel?
учитывая StackPanel:
<StackPanel>
<TextBox Height="30">Apple</TextBox>
<TextBox Height="80">Banana</TextBox>
<TextBox Height="120">Cherry</TextBox>
</StackPanel>
каков наилучший способ разместить дочерние элементы так, чтобы между ними были промежутки одинакового размера, даже если сами дочерние элементы имеют разные размеры? Можно ли это сделать без установки свойств для каждого из отдельных детей?
10 ответов:
используйте поля или отступы, применяемые к области внутри контейнера:
<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>Это самый простой и быстрый способ установить маржу для нескольких детей из группы, даже если они не одного типа. (Т. е. кнопки, текстовые поля, ComboBoxes и т. д.)
- добавьте свойство LastItemMargin в MarginSetter, чтобы специально обработать последний элемент
- добавить вложенное свойство Spacing с вертикальными и горизонтальными свойствами, которое добавляет расстояние между элементами в вертикальных и горизонтальных списках и устраняет любое конечное поле в конце списка
пример:
<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>
+1 для ответа Сергея. И если вы хотите применить это ко всем вашим StackPanels можно сделать так:
<Style TargetType="{x:Type StackPanel}"> <Style.Resources> <Style TargetType="{x:Type TextBox}"> <Setter Property="Margin" Value="{StaticResource tbMargin}"/> </Style> </Style.Resources> </Style>но будьте осторожны: если вы определяете такой стиль в своем приложении.xaml (или другой словарь, который объединяется в приложение.Ресурсы) это можете переопределить стиль элемента управления по умолчанию. Для большинства безликих элементов управления, таких как stackpanel, это не проблема, но для текстовых полей и т. д. Вы можете наткнуться на проблема, которым к счастью, есть некоторые обходные пути.
следуя предложению Сергея, Вы можете определить и повторно использовать весь стиль (с различными настройщиками свойств, включая поля) вместо просто объекта толщины:
<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) словаре ресурсов.
Sidenote:
во-первых, я наивно попытался использовать неявный стиль, чтобы установить свойство Style элемента управления для этого внешнего ресурса стиля (скажем, определенного с помощью ключа "MyStyle"):
<StackPanel> <StackPanel.Resources> <Style TargetType="SomeItemType"> <Setter Property="Style" Value={StaticResource MyStyle}" /> </Style> </StackPanel.Resources> </StackPanel>что привело к немедленному завершению работы Visual Studio 2010 с катастрофической ошибкой сбоя (HRESULT: 0x8000FFFF (E_UNEXPECTED)), как описано на https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails-with-catastrophic-failure-when-a-style-tries-to-set-style-property#
UniformGrid может быть недоступен в Silverlight, но кто-то портировал его из WPF. http://www.jeff.wilcox.name/2009/01/uniform-grid/
решетки.ColumnSpacing,решетки.RowSpacing,StackPanel.Расстояние сейчас на UWP на предварительный просмотр, все, что позволит лучше сделать то, что предлагается здесь.
эти свойства в настоящее время доступны только с Windows 10 Fall Creators Update Insider SDK, но должны сделать это до последних бит!
мой подход наследует 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(); } } }
иногда вам нужно установить отступ, а не маржу, чтобы сделать пространство между элементами меньше, чем по умолчанию

Comments