How to set margin for inner controls of WrapPanel
Here is an example that I'm using:
<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>
As you can see, my wrap panel has several buttons. Each button has the same margin and padding.
The question is, is there a way of setting margin and padding for wrap panel, so each element inside the wrap panel may use it values?
For setting inner element's font, i may use "TextElement" attached property provider. Is there similar way how i can set margin and padding for inner controls?
This make the code shorter and let me specify Margin and Padding only one time instead of setting it for each control in the panel.
Thank you!
The solution provided by James Hay is the easiest way to achieve your desired result.
However, there are other possible solutions:
- You could implement your own attached property/behavior for a
WrapPanel
which sets theMargin
and/orPadding
for all its children. See this CodeProject article by Josh Smith for details. - You could create your own panel which inherits from
WrapPanel
and just adds the required properties and overrides the appropriate methods, so that theMargin
/Padding
is set for all child elements. - You could also move the
Style
definition from theWindow.Resources
to theWrapPanel.Resources
, remove thex:Key
attribute from theStyle
, and remove theStyle="{StaticResource ButtonStyle}"
from allButton
s. This way, theStyle
is applied to allButton
s which are children of theWrapPanel
. If you also have other controls as children, you could change theTargetType
for theStyle
to an appropriate common base type (e.g.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>
Note, however, that this will influence all Button
instances within the WrapPanel
, not only its direct children!
Another nice approach can be seen here: http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between-items-in-stackpanel.aspx
It shows how to create an attached behavior, so that syntax like this would work:
<StackPanel local:MarginSetter.Margin="5">
<TextBox Text="hello" />
<Button Content="hello" />
<Button Content="hello" />
</StackPanel>
This is the easiest & fastest way to set Margin to several children of a panel, even if they are not of the same type. (I.e. Buttons, TextBoxes, ComboBoxes, etc.)
WrapPanel does not have any properties that add padding or margins to all its children. What you probably want is a style that is share by each button. Something like:
<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>
Here is a customized WrapPanel control that adds an ItemMargin dependency property.
/// <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;
}
}
}
Now you can just do:
<Style
x:Key="MarginWrapPanelStyle"
TargetType="{x:Type mycustomcontrols:ItemMarginWrapPanel}">
<Setter
Property="ItemMargin"
Value="5" />
</Style>
In case there are not many items in the panel, you could use a Line control and give it a width in case of WrapPanel and height in case of StackPanel. Then you could style the Line.
<WrapPanel Orientation="Horizontal" >
<Button Content="test1" />
<Line Width="15" />
<Button Content="test2" />
<Line Width="15" />
<Button Content="test3" />
</WrapPanel>
精彩评论