Как установить маржу для внутренних элементов управления WrapPanel
Я новичок в WPF и задаюсь вопросом.
Вот пример, который я использую:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<WrapPanel Orientation="Horizontal" TextElement.FontSize="30" TextElement.FontStyle="Italic" >
<Button Content="test1" Margin="10,0" Padding="10,10" />
<Button Content="test2" Margin="10,0" Padding="10,10" />
<Button Content="test3" Margin="10,0" Padding="10,10" />
<Button Content="test4" Margin="10,0" Padding="10,10" />
<Button Content="test5" Margin="10,0" Padding="10,10" />
</WrapPanel>
</StackPanel>
Как вы можете видеть, моя панель обложки имеет несколько кнопок.
Каждая кнопка имеет одинаковый запас и отступ.
Вопрос в том, есть ли способ установки поля и заполнения для панели обертки, так что каждый элемент внутри панели обертки может использовать его значения?
Для установки шрифта внутреннего элемента я могу использовать приложенный поставщик свойств "TextElement". Есть ли аналогичный способ, как я могу установить margin и padding для внутренних элементов управления?
Это делает код короче и позволяет мне указывать Margin и Padding только один раз вместо того, чтобы устанавливать его для каждого элемента управления на панели.
Спасибо!
Ответы
Ответ 1
Решение, предоставленное James Hay, - это самый простой способ достичь желаемого результата.
Однако существуют и другие возможные решения:
- Вы можете реализовать свое собственное вложенное свойство/поведение для
WrapPanel
, которое устанавливает Margin
и/или Padding
для всех его дочерних элементов. Подробнее см. эту статью CodeProject от Josh Smith.
- Вы можете создать свою собственную панель, которая наследует от
WrapPanel
, и просто добавляет необходимые свойства и переопределяет соответствующие методы, так что для всех дочерних элементов устанавливается Margin
/Padding
.
- Вы также можете перенести определение
Style
с Window.Resources
на WrapPanel.Resources
, удалить атрибут x:Key
из Style
и удалить Style="{StaticResource ButtonStyle}"
из всех Button
s. Таким образом, Style
применяется ко всем Button
, которые являются дочерними элементами WrapPanel
. Если у вас также есть другие элементы управления в качестве дочерних элементов, вы можете изменить TargetType
для Style
на соответствующий общий базовый тип (например, FrameworkElement
):
<StackPanel>
<WrapPanel Orientation="Horizontal">
<WrapPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10,0" />
<Setter Property="Padding" Value="10,10" />
</Style>
</WrapPanel.Resources>
<Button Content="test1" />
<Button Content="test2" />
<Button Content="test3" />
<Button Content="test4" />
<Button Content="test5" />
</WrapPanel>
</StackPanel>
Обратите внимание, что это повлияет на все экземпляры Button
в WrapPanel
, а не только на его прямые дочерние элементы!
Ответ 2
Еще один приятный подход можно увидеть здесь:
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>
Это самый простой и быстрый способ установить Margin для нескольких дочерних элементов панели, даже если они не одного типа. (I.e. Buttons, TextBoxes, ComboBoxes и т.д.)
Ответ 3
У WrapPanel нет никаких свойств, которые добавили бы отступы или поля для всех его дочерних элементов. То, что вы, вероятно, хотите, это стиль, который является общим для каждой кнопки. Что-то вроде:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10,0" />
<Setter Property="Padding" Value="10,10" />
</Style>
</Window.Resources>
<StackPanel>
<WrapPanel Orientation="Horizontal" >
<Button Content="test1" Style="{StaticResource ButtonStyle}" />
<Button Content="test2" Style="{StaticResource ButtonStyle}" />
<Button Content="test3" Style="{StaticResource ButtonStyle}" />
<Button Content="test4" Style="{StaticResource ButtonStyle}" />
<Button Content="test5" Style="{StaticResource ButtonStyle}" />
</WrapPanel>
</StackPanel>
</Window>
Ответ 4
Вот настраиваемый элемент управления WrapPanel, который добавляет свойство зависимостей ItemMargin.
/// <summary>
/// A wrap panel which can apply a margin to each child item.
/// </summary>
public class ItemMarginWrapPanel : WrapPanel
{
/// <summary>
/// ItemMargin static DP.
/// </summary>
public static readonly DependencyProperty ItemMarginProperty =
DependencyProperty.Register(
"ItemMargin",
typeof( Thickness ),
typeof( ItemMarginWrapPanel ),
new FrameworkPropertyMetadata(
new Thickness(),
FrameworkPropertyMetadataOptions.AffectsMeasure ) );
/// <summary>
/// The margin that will be applied to each Item in the wrap panel.
/// </summary>
public Thickness ItemMargin
{
get
{
return (Thickness)GetValue( ItemMarginProperty );
}
set
{
SetValue( ItemMarginProperty, value );
}
}
/// <summary>
/// Overridden. Sets item margins before calling base implementation.
/// </summary>
/// <param name="constraint"></param>
/// <returns></returns>
protected override Size MeasureOverride( Size constraint )
{
RefreshItemMargin();
return base.MeasureOverride( constraint );
}
/// <summary>
/// Overridden. Sets item margins before calling base implementation.
/// </summary>
/// <param name="finalSize"></param>
/// <returns></returns>
protected override Size ArrangeOverride( Size finalSize )
{
RefreshItemMargin();
return base.ArrangeOverride( finalSize );
}
/// <summary>
/// Refresh the child item margins.
/// </summary>
private void RefreshItemMargin()
{
var children = InternalChildren;
for( int i = 0, count = children.Count; i < count; i++ )
{
var ele = children[i] as FrameworkElement;
if( null != ele )
ele.Margin = ItemMargin;
}
}
}
Теперь вы можете просто сделать:
<Style
x:Key="MarginWrapPanelStyle"
TargetType="{x:Type mycustomcontrols:ItemMarginWrapPanel}">
<Setter
Property="ItemMargin"
Value="5" />
</Style>
Ответ 5
В случае, если на панели не так много элементов, вы можете использовать элемент управления Line и дать ему ширину в случае WrapPanel и высоты в случае StackPanel. Затем вы можете создать линию.
<WrapPanel Orientation="Horizontal" >
<Button Content="test1" />
<Line Width="15" />
<Button Content="test2" />
<Line Width="15" />
<Button Content="test3" />
</WrapPanel>