WPF:带有列/行边距/填充的网格?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1319974/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF: Grid with column/row margin/padding?
提问by Brad Leach
Is it easily possible to specify a margin and/or padding for rows or columns in a WPF Grid?
是否可以轻松地为 WPF 网格中的行或列指定边距和/或填充?
I could of course add extra columns to space things out, but this seems like a job for padding/margins (it will give muchsimplier XAML). Has someone derived from the standard Grid to add this functionality?
我当然可以添加额外的列以将内容隔开,但这似乎是填充/边距的工作(它会提供更简单的 XAML)。是否有人从标准网格派生来添加此功能?
采纳答案by Thomas Levesque
You could write your own GridWithMargin
class, inherited from Grid
, and override the ArrangeOverride
method to apply the margins
您可以编写自己的GridWithMargin
类,继承自Grid
,并覆盖该ArrangeOverride
方法以应用边距
回答by Charlie
RowDefinition
and ColumnDefinition
are of type ContentElement
, and Margin
is strictly a FrameworkElement
property. So to your question, "is it easily possible"the answer is a most definite no. And no, I have not seen any layout panels that demonstrate this kind of functionality.
RowDefinition
和ColumnDefinition
是 类型ContentElement
,并且Margin
是严格的FrameworkElement
属性。所以对于你的问题,“这很容易吗”,答案是绝对的。不,我还没有看到任何展示这种功能的布局面板。
You can add extra rows or columns as you suggested. But you can also set margins on a Grid
element itself, or anything that would go inside a Grid
, so that's your best workaround for now.
您可以按照建议添加额外的行或列。但是您也可以设置Grid
元素本身的边距,或者任何可以进入 的东西Grid
,所以这是目前最好的解决方法。
回答by samad
Use a Border
control outside the cell control and define the padding for that:
使用Border
单元格控件之外的控件并为其定义填充:
<Grid>
<Grid.Resources >
<Style TargetType="Border" >
<Setter Property="Padding" Value="5,5,5,5" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Grid.Column="0">
<YourGridControls/>
</Border>
<Border Grid.Row="1" Grid.Column="0">
<YourGridControls/>
</Border>
</Grid>
Source:
来源:
回答by JayGee
You could use something like this:
你可以使用这样的东西:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
Or if you don't need the TemplateBindings:
或者,如果您不需要 TemplateBindings:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="4">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
回答by James M
Thought I'd add my own solution because nobody yet mentioned this. Instead of designing a UserControl based on Grid, you can target controls contained in grid with a style declaration. Takes care of adding padding/margin to all elements without having to define for each, which is cumbersome and labor-intensive.For instance, if your Grid contains nothing but TextBlocks, you can do this:
以为我会添加自己的解决方案,因为还没有人提到这一点。您可以使用样式声明来定位包含在网格中的控件,而不是基于 Grid 设计 UserControl。负责为所有元素添加填充/边距,而不必为每个元素定义,这既麻烦又费力。例如,如果您的 Grid 只包含 TextBlocks,您可以这样做:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"/>
</Style>
Which is like the equivalent of "cell padding".
这相当于“单元格填充”。
回答by 15ee8f99-57ff-4f92-890c-b56153
This is not terribly difficult. I can't say how difficult it was in 2009 when the question was asked, but that was then.
这并不是非常困难。我不能说 2009 年提出这个问题时有多困难,但那是当时。
Note that if you explicitly set a margin directly on a child of the grid when using this solution, that margin will appear in the designer but not at runtime.
请注意,如果您在使用此解决方案时直接在网格的子项上显式设置边距,则该边距将出现在设计器中,但不会在运行时出现。
This property can be applied to Grid, StackPanel, WrapPanel, UniformGrid, or any other descendant of Panel. It affects immediate children. It's presumed that children will want to manage the layout of their own contents.
此属性可应用于 Grid、StackPanel、WrapPanel、UniformGrid 或 Panel 的任何其他后代。它会影响直接的孩子。假设孩子们想要管理他们自己内容的布局。
PanelExt.cs
面板扩展程序
public static class PanelExt
{
public static Thickness? GetChildMargin(Panel obj)
{
return (Thickness?)obj.GetValue(ChildMarginProperty);
}
public static void SetChildMargin(Panel obj, Thickness? value)
{
obj.SetValue(ChildMarginProperty, value);
}
/// <summary>
/// Apply a fixed margin to all direct children of the Panel, overriding all other margins.
/// Panel descendants include Grid, StackPanel, WrapPanel, and UniformGrid
/// </summary>
public static readonly DependencyProperty ChildMarginProperty =
DependencyProperty.RegisterAttached("ChildMargin", typeof(Thickness?), typeof(PanelExt),
new PropertyMetadata(null, ChildMargin_PropertyChanged));
private static void ChildMargin_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as Panel;
target.Loaded += (s, e2) => ApplyChildMargin(target, (Thickness?)e.NewValue);
ApplyChildMargin(target, (Thickness?)e.NewValue);
}
public static void ApplyChildMargin(Panel panel, Thickness? margin)
{
int count = VisualTreeHelper.GetChildrenCount(panel);
object value = margin.HasValue ? margin.Value : DependencyProperty.UnsetValue;
for (var i = 0; i < count; ++i)
{
var child = VisualTreeHelper.GetChild(panel, i) as FrameworkElement;
if (child != null)
{
child.SetValue(FrameworkElement.MarginProperty, value);
}
}
}
}
Demo:
演示:
MainWindow.xaml
主窗口.xaml
<Grid
local:PanelExt.ChildMargin="2"
x:Name="MainGrid"
>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Width="100" Height="40" Fill="Red" Grid.Row="0" Grid.Column="0" />
<Rectangle Width="100" Height="40" Fill="Green" Grid.Row="1" Grid.Column="0" />
<Rectangle Width="100" Height="40" Fill="Blue" Grid.Row="1" Grid.Column="1" />
<Button Grid.Row="2" Grid.Column="0" Click="NoMarginClick">No Margin</Button>
<Button Grid.Row="2" Grid.Column="1" Click="BigMarginClick">Big Margin</Button>
<ComboBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>
MainWindow.xaml.cs
主窗口.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void NoMarginClick(object sender, RoutedEventArgs e)
{
// In real life, if we wanted to change PanelExt.ChildMargin at runtime, we
// would prefer to bind it to something, probably a dependency property of
// the view. But this will do for a demonstration.
PanelExt.SetChildMargin(MainGrid, null);
}
private void BigMarginClick(object sender, RoutedEventArgs e)
{
PanelExt.SetChildMargin(MainGrid, new Thickness(20));
}
}
回答by Kursat Turkay
in uwp (Windows10FallCreatorsUpdate version and above)
在 uwp(Windows10FallCreatorsUpdate 版本及以上)
<Grid RowSpacing="3" ColumnSpacing="3">
回答by Matt Meikle
I ran into this problem while developing some software recently and it occured to me to ask WHY? Why have they done this...the answer was right there in front of me. A row of data is an object, so if we maintain object orientation, then the design for a particular row should be seperated (suppose you need to re-use the row display later on in the future). So I started using databound stack panels and custom controls for most data displays. Lists have made the occasional appearance but mostly the grid has been used only for primary page organization (Header, Menu Area, Content Area, Other Areas). Your custom objects can easily manage any spacing requirements for each row within the stack panel or grid (a single grid cell can contain the entire row object. This also has the added benefit of reacting properly to changes in orientation, expand/collapses, etc.
最近在开发一些软件时遇到了这个问题,突然想问问为什么?他们为什么要这样做……答案就在我面前。一行数据是一个对象,所以如果我们保持面向对象,那么特定行的设计应该是分开的(假设您以后需要重新使用行显示)。所以我开始对大多数数据显示使用数据绑定堆栈面板和自定义控件。列表偶尔出现,但大部分网格仅用于主页面组织(页眉、菜单区域、内容区域、其他区域)。您的自定义对象可以轻松管理堆栈面板或网格中每一行的任何间距要求(单个网格单元可以包含整个行对象。这还具有对方向变化做出正确反应的额外好处,
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</Grid>
or
或者
<StackPanel>
<custom:MyRowObject Style="YourStyleHere" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</StackPanel>
Your Custom controls will also inherit the DataContext if your using data binding...my personal favorite benefit of this approach.
如果您使用数据绑定,您的自定义控件也将继承 DataContext...我个人最喜欢这种方法的好处。
回答by isierra
I did it right now with one of my grids.
我现在用我的一个网格做到了。
- First apply the same margin to every element inside the grid. You can do this mannualy, using styles, or whatever you like. Lets say you want an horizontal spacing of 6px and a vertical spacing of 2px. Then you add margins of "3px 1px" to every child of the grid.
- Then remove the margins created around the grid (if you want to align the borders of the controls inside the grid to the same position of the grid). Do this setting a margin of "-3px -1px" to the grid. That way, other controls outside the grid will be aligned with the outtermost controls inside the grid.
- 首先对网格内的每个元素应用相同的边距。您可以使用样式或任何您喜欢的方式手动执行此操作。假设您想要 6px 的水平间距和 2px 的垂直间距。然后为网格的每个子元素添加“3px 1px”的边距。
- 然后删除在网格周围创建的边距(如果要将网格内的控件边框与网格的相同位置对齐)。这样做会为网格设置“-3px -1px”的边距。这样,网格外的其他控件将与网格内的最外面的控件对齐。
回答by Juan Pablo
Edited:
编辑:
To give margin to any control you could wrap the control with border like this
要为任何控件提供边距,您可以像这样用边框包裹控件
<!--...-->
<Border Padding="10">
<AnyControl>
<!--...-->