Files
Shrlalgo.RvKits/Melskin/Layout/TableGrid.cs
2026-02-17 22:17:13 +08:00

194 lines
6.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace Melskin.Layout
{
/// <summary>
/// 表格网格控件继承自Grid用于以表格形式排列子元素。
/// 通过设置列数和间距属性,可以控制子元素在表格中的布局方式。
/// </summary>
public class TableGrid:System.Windows.Controls.Grid
{
#region Spacing
/// <summary>
/// 获取或设置表格网格中单元格之间的间距。
/// 该属性控制表格中每个单元格在水平和垂直方向上的间隔大小。
/// </summary>
/// <value>一个表示间距的 <see cref="Size"/> 结构,其中 <see cref="Size.Width"/> 控制列间距,<see cref="Size.Height"/> 控制行间距。</value>
/// <remarks>
/// 更改此属性将触发布局更新,以确保所有子元素根据新的间距值重新排列。
/// </remarks>
public Size Spacing
{
get => spacing;
set
{
if (value != spacing)
SetValue(SpacingProperty, value);
}
}
private Size spacing;
/// <summary>
/// 表示表格网格中单元格间距的依赖属性。
/// 该属性用于定义表格内每个单元格在水平和垂直方向上的间隔大小,通过<see cref="Size"/>结构来表示,其中<see cref="Size.Width"/>部分控制列间距,<see cref="Size.Height"/>部分控制行间距。
/// </summary>
/// <remarks>
/// 当此属性值发生变化时,会触发布局更新机制,以确保所有子元素能够根据新的间距值重新排列。这有助于保持布局的一致性和美观性。
/// </remarks>
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register(
nameof(Spacing),
typeof(Size),
typeof(TableGrid),
new PropertyMetadata(
default(Size),
(s, e) =>
{
var self = (TableGrid) s;
self.spacing = (Size) e.NewValue;
self.UpdateColumns();
}));
#endregion
#region Columns
/// <summary>
/// 获取或设置表格网格中的列数。
/// </summary>
/// <remarks>
/// 当更改此属性时,会自动调整行和列的布局以适应新的列数,并重新排列子元素的位置。此属性影响测量过程。
/// </remarks>
public int Columns
{
get => columns;
set
{
if (value != columns)
SetValue(ColumnsProperty, value);
}
}
private int columns;
/// <summary>
/// 获取或设置表格网格中的列数。
/// 该属性定义了表格中将包含多少列,从而影响子元素的布局方式。
/// </summary>
/// <value>一个整数值,表示表格网格中的列数。</value>
/// <remarks>
/// 更改此属性会触发布局更新,确保所有子元素根据新的列数重新排列。如果设置了新的列数,则会对整个表格进行测量和排列以适应更改。
/// </remarks>
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register(
nameof(Columns),
typeof(int),
typeof(TableGrid),
new FrameworkPropertyMetadata(
0,
FrameworkPropertyMetadataOptions.AffectsMeasure,
(s, e) =>
{
var self = (TableGrid) s;
self.columns = (int) e.NewValue;
self.UpdateColumns();
}));
#endregion
private void UpdateColumns()
{
var childCount = VisualTreeHelper.GetChildrenCount(this);
{
while (ColumnDefinitions.Count < childCount)
{
var cd = new ColumnDefinition
{
Width = new GridLength(0, GridUnitType.Auto)
};
ColumnDefinitions.Add(cd);
}
while (ColumnDefinitions.Count > childCount)
ColumnDefinitions.RemoveAt(ColumnDefinitions.Count - 1);
}
{
var rows = childCount / Columns;
while (RowDefinitions.Count < rows)
{
var rd = new RowDefinition
{
Height = new GridLength(0, GridUnitType.Star)
};
RowDefinitions.Add(rd);
}
while (RowDefinitions.Count > rows)
RowDefinitions.RemoveAt(RowDefinitions.Count - 1);
}
{
var columnCount = 0;
var rowCount = 0;
var rows = childCount / Columns;
var isLastRow = rowCount == rows - 1;
for (var i = 0; i != childCount; ++i)
{
var child = (FrameworkElement) VisualTreeHelper.GetChild(this, i);
SetColumn(child, columnCount);
SetRow(child, rowCount);
var isLastItem = i == childCount - 1;
var px = columnCount == Columns - 1 || isLastItem
? 0d
: Spacing.Width;
var py = isLastRow || isLastItem
? 0d
: Spacing.Height;
child.Margin = new Thickness(0d, 0d, px, py);
++columnCount;
if (columnCount == Columns)
{
columnCount = 0;
++rowCount;
isLastRow = rowCount == rows - 1;
}
}
}
}
/// <inheritdoc />
protected override Size ArrangeOverride(Size arrangeSize)
{
if (!isRequestUpdateColumns) return base.ArrangeOverride(arrangeSize);
UpdateColumns();
isRequestUpdateColumns = false;
return base.ArrangeOverride(arrangeSize);
}
private bool isRequestUpdateColumns;
/// <inheritdoc />
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
{
isRequestUpdateColumns = true;
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
}
}
}