mirror of
https://github.com/crskycode/GARbro.git
synced 2024-11-27 15:44:00 +08:00
93c4911bfa
Grid that addes ChildMargin to its children
108 lines
4.7 KiB
C#
108 lines
4.7 KiB
C#
// http://daniel-albuschat.blogspot.ru/2011/07/gridlayout-for-wpf-escape-margin-hell.html
|
|
//
|
|
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
|
|
namespace GridLayoutTest
|
|
{
|
|
// The GridLayout is a special Panel that can be used exactly like the Grid Panel, except that it
|
|
// defines a new property ChildMargin. ChildMargin's left, top, right and bottom margins will be applied
|
|
// to all children in a way that the children will have a vertical space of ChildMargin.Top+ChildMargin.Bottom
|
|
// and a horizontal space of ChildMargin.Left+ChildMargin.Right between them.
|
|
// However, there is no margin for the borders of the internal widget, so that the GridLayout itself can be
|
|
// aligned to another element without a margin.
|
|
// It's best to have a look at TestWindow, which effectively tests all possible alignments of children.
|
|
|
|
public class GridLayout : Grid
|
|
{
|
|
public static readonly DependencyProperty ChildMarginProperty = DependencyProperty.Register(
|
|
"ChildMargin",
|
|
typeof(Thickness),
|
|
typeof(GridLayout),
|
|
new FrameworkPropertyMetadata(new Thickness (5))
|
|
{
|
|
AffectsArrange = true,
|
|
AffectsMeasure = true
|
|
});
|
|
// The child margin defines a margin that will be automatically applied to all children of this Grid.
|
|
// However, the children at the edges will have the respective margins remove. E.g. the leftmost children will have
|
|
// a Margin.Left of 0 and the children in the first row will have a Margin.Top of 0.
|
|
// The margins that are not set to 0 are set to half the ChildMargin's value, since it's neighbour will also apply it,
|
|
// effectively doubling it.
|
|
|
|
public Thickness ChildMargin
|
|
{
|
|
get { return (Thickness)GetValue(ChildMarginProperty); }
|
|
set
|
|
{
|
|
SetValue(ChildMarginProperty, value);
|
|
UpdateChildMargins();
|
|
}
|
|
}
|
|
|
|
// UpdateChildMargin first finds out what's the rightmost column and bottom row and then applies
|
|
// the correct margins to all children.
|
|
|
|
public void UpdateChildMargins()
|
|
{
|
|
int maxColumn = 0;
|
|
int maxRow = 0;
|
|
foreach (UIElement element in InternalChildren)
|
|
{
|
|
int row = GetRow(element);
|
|
int rowSpan = GetRowSpan(element);
|
|
int column = GetColumn(element);
|
|
int columnSpan = GetColumnSpan(element);
|
|
|
|
if (row + rowSpan > maxRow)
|
|
maxRow = row + rowSpan;
|
|
if (column + columnSpan> maxColumn)
|
|
maxColumn = column + columnSpan;
|
|
}
|
|
foreach (UIElement element in InternalChildren)
|
|
{
|
|
FrameworkElement fe = element as FrameworkElement;
|
|
if (null != fe)
|
|
{
|
|
int row = GetRow(fe);
|
|
int rowSpan = GetRowSpan(fe);
|
|
int column = GetColumn(fe);
|
|
int columnSpan = GetColumnSpan(fe);
|
|
double factorLeft = 0.5;
|
|
double factorTop = 0.5;
|
|
double factorRight = 0.5;
|
|
double factorBottom = 0.5;
|
|
// Top row - no top margin
|
|
if (row == 0)
|
|
factorTop = 0;
|
|
// Bottom row - no bottom margin
|
|
if (row + rowSpan >= maxRow)
|
|
factorBottom = 0;
|
|
// Leftmost column = no left margin
|
|
if (column == 0)
|
|
factorLeft = 0;
|
|
// Rightmost column - no right margin
|
|
if (column + columnSpan >= maxColumn)
|
|
factorRight = 0;
|
|
fe.Margin = new Thickness (ChildMargin.Left * factorLeft,
|
|
ChildMargin.Top * factorTop,
|
|
ChildMargin.Right * factorRight,
|
|
ChildMargin.Bottom * factorBottom);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We change all children's margins in MeasureOverride, since this is called right before
|
|
// the layouting takes place. I was first skeptical to do this here, because I thought changing
|
|
// the margin will trigger a LayoutUpdate, which in turn would lead to an endless recursion,
|
|
// but apparantly WPF takes care of this.
|
|
|
|
protected override Size MeasureOverride(Size availableSize)
|
|
{
|
|
UpdateChildMargins();
|
|
return base.MeasureOverride(availableSize);
|
|
}
|
|
}
|
|
}
|