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

256 lines
9.0 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.
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;
}
}