Files
qhmes/yy-admin-master/YY.Admin.Core/Controls/GridPanel.cs

256 lines
9.0 KiB
C#
Raw Normal View History

using System.Windows;
using System.Windows.Controls;
namespace YY.Admin.Core.Controls;
public class GridPanel : Panel
{
// ------------------------------------------------------------
// 间距属性(行列间距)
// ------------------------------------------------------------
public double Gap
{
get => (double)GetValue(GapProperty);
set => SetValue(GapProperty, value);
}
public static readonly DependencyProperty GapProperty =
DependencyProperty.Register(nameof(Gap), typeof(double), typeof(GridPanel),
new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
// ------------------------------------------------------------
// 横向/纵向布局(类似 CSS flow
// ------------------------------------------------------------
public Orientation Orientation
{
get => (Orientation)GetValue(OrientationProperty);
set => SetValue(OrientationProperty, value);
}
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(GridPanel),
new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
// ------------------------------------------------------------
// 测量
// ------------------------------------------------------------
protected override Size MeasureOverride(Size availableSize)
{
return Orientation == Orientation.Horizontal
? MeasureHorizontal(availableSize)
: MeasureVertical(availableSize);
}
// ------------------------------------------------------------
// 布局
// ------------------------------------------------------------
protected override Size ArrangeOverride(Size finalSize)
{
return Orientation == Orientation.Horizontal
? ArrangeHorizontal(finalSize)
: ArrangeVertical(finalSize);
}
// ------------------------------------------------------------
// 横向布局(类似 CSS grid-template-columns
// ------------------------------------------------------------
private Size MeasureHorizontal(Size availableSize)
{
double panelWidth = double.IsInfinity(availableSize.Width)
? MinWidth * 4 + Gap * 3
: availableSize.Width;
// ---- 修复:不能用 MinWidth+Gap 来估算列数,应使用最小子项宽度 ----
double minChildWidth = MinWidth <= 0 ? 1 : MinWidth;
// ---- 修复:列数 = 能放下多少个最小宽度 ----
int columnCount = Math.Max(1, (int)Math.Floor((panelWidth + Gap) / (minChildWidth + Gap)));
int childCount = InternalChildren.Count;
// ---- 修复2如果列数超过子项数裁到子项数实现 auto-fit 行为) ----
if (childCount > 0 && columnCount > childCount)
{
columnCount = childCount;
}
double columnWidth = (panelWidth - Gap * (columnCount - 1)) / columnCount;
double totalHeight = 0;
double rowHeight = 0;
int col = 0;
for (int i = 0; i < childCount; i++)
{
UIElement child = InternalChildren[i];
child.Measure(new Size(columnWidth, double.PositiveInfinity));
rowHeight = Math.Max(rowHeight, child.DesiredSize.Height);
col++;
if (col >= columnCount || i == childCount - 1)
{
// ------------------------------------------------------------
// 最后一行不加Gap
// ------------------------------------------------------------
totalHeight += rowHeight;
if (i != childCount - 1) totalHeight += Gap;
col = 0;
rowHeight = 0;
}
}
return new Size(panelWidth, totalHeight);
}
private Size ArrangeHorizontal(Size finalSize)
{
double panelWidth = finalSize.Width;
// ---- 修复:与 Measure 保持一致 ----
double minChildWidth = MinWidth <= 0 ? 1 : MinWidth;
int columnCount = Math.Max(1, (int)Math.Floor((panelWidth + Gap) / (minChildWidth + Gap)));
int childCount = InternalChildren.Count;
// ---- 修复2裁到子项数以实现 auto-fit ----
if (childCount > 0 && columnCount > childCount)
{
columnCount = childCount;
}
double columnWidth = (panelWidth - Gap * (columnCount - 1)) / columnCount;
double x = 0;
double y = 0;
double rowHeight = 0;
int col = 0;
for (int i = 0; i < childCount; i++)
{
UIElement child = InternalChildren[i];
// 为了保证每列宽度一致,传入 columnWidth 并在 Arrange 时使用 columnWidth
child.Arrange(new Rect(x, y, columnWidth, child.DesiredSize.Height));
rowHeight = Math.Max(rowHeight, child.DesiredSize.Height);
col++;
if (col >= columnCount || i == childCount - 1)
{
x = 0;
// ------------------------------------------------------------
// 最后一行不加Gap
// ------------------------------------------------------------
if (i != childCount - 1) y += rowHeight + Gap;
else y += rowHeight;
col = 0;
rowHeight = 0;
}
else
{
x += columnWidth + Gap;
}
}
return finalSize;
}
// ------------------------------------------------------------
// 纵向布局(类似 CSS grid-template-rows
// ------------------------------------------------------------
private Size MeasureVertical(Size availableSize)
{
double panelHeight = double.IsInfinity(availableSize.Height)
? MinHeight * 4 + Gap * 3
: availableSize.Height;
// ---- 修复:使用最小子项高度,不能用 MinHeight+Gap ----
double minChildHeight = MinHeight <= 0 ? 1 : MinHeight;
// ---- 修复:行数 = 能放下多少个最小高度 ----
int rowCount = Math.Max(1, (int)Math.Floor((panelHeight + Gap) / (minChildHeight + Gap)));
int childCount = InternalChildren.Count;
// ---- 修复2如果行数超过子项数裁到子项数auto-fit ----
if (childCount > 0 && rowCount > childCount)
{
rowCount = childCount;
}
double rowHeight = (panelHeight - Gap * (rowCount - 1)) / rowCount;
double totalWidth = 0;
double columnWidth = 0;
int row = 0;
for (int i = 0; i < childCount; i++)
{
UIElement child = InternalChildren[i];
child.Measure(new Size(double.PositiveInfinity, rowHeight));
columnWidth = Math.Max(columnWidth, child.DesiredSize.Width);
row++;
if (row >= rowCount || i == childCount - 1)
{
// ------------------------------------------------------------
// 最后一列不加Gap
// ------------------------------------------------------------
totalWidth += columnWidth;
if (i != childCount - 1) totalWidth += Gap;
row = 0;
columnWidth = 0;
}
}
return new Size(totalWidth, panelHeight);
}
private Size ArrangeVertical(Size finalSize)
{
double panelHeight = finalSize.Height;
// ---- 修复:与 MeasureVertical 一致 ----
double minChildHeight = MinHeight <= 0 ? 1 : MinHeight;
int rowCount = Math.Max(1, (int)Math.Floor((panelHeight + Gap) / (minChildHeight + Gap)));
int childCount = InternalChildren.Count;
// ---- 修复2裁到子项数 ----
if (childCount > 0 && rowCount > childCount)
{
rowCount = childCount;
}
double rowHeight = (panelHeight - Gap * (rowCount - 1)) / rowCount;
double x = 0;
double y = 0;
double columnWidth = 0;
int row = 0;
for (int i = 0; i < childCount; i++)
{
UIElement child = InternalChildren[i];
child.Arrange(new Rect(x, y, child.DesiredSize.Width, rowHeight));
columnWidth = Math.Max(columnWidth, child.DesiredSize.Width);
row++;
if (row >= rowCount || i == childCount - 1)
{
// ------------------------------------------------------------
// 最后一列不加Gap
// ------------------------------------------------------------
x += columnWidth;
if (i != childCount - 1) x += Gap;
y = 0;
row = 0;
columnWidth = 0;
}
else
{
y += rowHeight + Gap;
}
}
return finalSize;
}
}