779 lines
22 KiB
C#
779 lines
22 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Linq;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
|
||
using Wpf.Ui.Extend.Extensions;
|
||
|
||
namespace Wpf.Ui.Extend.Layouts;
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <remarks>注意整个XAML文档控件的顺序,使用Grid.Row和Grid.Column应逐行添加控件,对于嵌套的AutoGrid,其ChildMargin,HorizonAlignment,VerticalAlignment会继承</remarks>
|
||
public class AutoGrid : Grid
|
||
{
|
||
int rowOrColumnCount;
|
||
|
||
bool shouldReindex = true;
|
||
|
||
public AutoGrid()
|
||
{
|
||
Loaded += AutoGrid_Loaded;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用默认子边距和对齐等布局效果
|
||
/// </summary>
|
||
void ApplyChildDefaultLayout(UIElement child)
|
||
{
|
||
if (ChildMargin != null)
|
||
{
|
||
child.SetIfDefault(MarginProperty, ChildMargin.Value);
|
||
}
|
||
if (ChildHorizontalAlignment != null)
|
||
{
|
||
child.SetIfDefault(HorizontalAlignmentProperty, ChildHorizontalAlignment.Value);
|
||
}
|
||
if (ChildVerticalAlignment != null)
|
||
{
|
||
child.SetIfDefault(VerticalAlignmentProperty, ChildVerticalAlignment.Value);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 应用子边距和对齐等布局效果
|
||
/// </summary>
|
||
void ApplyChildLayout(UIElement child)
|
||
{
|
||
if (ChildMargin.HasValue)
|
||
{
|
||
child.SetValue(ChildMarginProperty, ChildMargin);
|
||
}
|
||
|
||
if (ChildHorizontalAlignment.HasValue)
|
||
{
|
||
child.SetValue(HorizontalAlignmentProperty, ChildHorizontalAlignment);
|
||
}
|
||
|
||
if (ChildVerticalAlignment.HasValue)
|
||
{
|
||
child.SetValue(VerticalAlignmentProperty, ChildVerticalAlignment);
|
||
}
|
||
}
|
||
|
||
private void AutoGrid_Loaded(object sender, RoutedEventArgs e)
|
||
{
|
||
Loaded -= AutoGrid_Loaded;
|
||
if (Children.Count == 0)
|
||
{
|
||
return;
|
||
}
|
||
foreach (UIElement elem in Children)
|
||
{
|
||
ApplyChildLayout(elem);
|
||
}
|
||
}
|
||
|
||
///// <summary>
|
||
///// 将某一数值限制在最大值。
|
||
///// </summary>
|
||
//int Clamp(int value, int max)
|
||
//{
|
||
// return value > max ? max : value;
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 从逗号分隔符文本中解析网格长度数组
|
||
/// </summary>
|
||
private static GridLength[] Parse(string text)
|
||
{
|
||
var tokens = text.Split(',');
|
||
var definitions = new GridLength[tokens.Length];
|
||
for (var i = 0; i < tokens.Length; i++)
|
||
{
|
||
var str = tokens[i];
|
||
double value;
|
||
|
||
// 占比
|
||
if (str.Contains('*'))
|
||
{
|
||
if (!double.TryParse(str.Replace("*", ""), out value))
|
||
value = 1.0;
|
||
|
||
definitions[i] = new GridLength(value, GridUnitType.Star);
|
||
continue;
|
||
}
|
||
|
||
// 像素
|
||
if (double.TryParse(str, out value))
|
||
{
|
||
definitions[i] = new GridLength(value);
|
||
continue;
|
||
}
|
||
if (str.Equals("auto", StringComparison.CurrentCultureIgnoreCase))
|
||
{
|
||
definitions[i] = GridLength.Auto;
|
||
}
|
||
//definitions[i] = GridLength.Auto;
|
||
}
|
||
return definitions;
|
||
}
|
||
|
||
private void PerformLayout()
|
||
{
|
||
var isVertical = Orientation == Orientation.Vertical;
|
||
|
||
if (
|
||
shouldReindex
|
||
|| IsAutoIndexing
|
||
&& (
|
||
isVertical && rowOrColumnCount != ColumnDefinitions.Count
|
||
|| !isVertical && rowOrColumnCount != RowDefinitions.Count
|
||
)
|
||
)
|
||
{
|
||
shouldReindex = false;
|
||
|
||
if (IsAutoIndexing)
|
||
{
|
||
rowOrColumnCount = ColumnDefinitions.Count != 0 ? ColumnDefinitions.Count : RowDefinitions.Count;
|
||
if (rowOrColumnCount == 0)
|
||
rowOrColumnCount = 1;
|
||
|
||
var cellCount = 0;
|
||
foreach (UIElement child in Children)
|
||
{
|
||
if (GetAutoIndex(child) == false)
|
||
{
|
||
continue;
|
||
}
|
||
cellCount += ColumnDefinitions.Count != 0 ? GetColumnSpan(child) : GetRowSpan(child);
|
||
}
|
||
|
||
// 更新行/列数
|
||
if (ColumnDefinitions.Count != 0)
|
||
{
|
||
var newRowCount = (int)Math.Ceiling(cellCount / (double)rowOrColumnCount);
|
||
while (RowDefinitions.Count < newRowCount)
|
||
{
|
||
var rowDefinition = new RowDefinition { Height = RowHeight };
|
||
RowDefinitions.Add(rowDefinition);
|
||
}
|
||
if (RowDefinitions.Count > newRowCount)
|
||
{
|
||
RowDefinitions.RemoveRange(newRowCount, RowDefinitions.Count - newRowCount);
|
||
}
|
||
}
|
||
else // 已定义的行
|
||
{
|
||
var newColumnCount = (int)Math.Ceiling(cellCount / (double)rowOrColumnCount);
|
||
while (ColumnDefinitions.Count < newColumnCount)
|
||
{
|
||
var columnDefinition = new ColumnDefinition { Width = ColumnWidth };
|
||
ColumnDefinitions.Add(columnDefinition);
|
||
}
|
||
if (ColumnDefinitions.Count > newColumnCount)
|
||
{
|
||
ColumnDefinitions.RemoveRange(newColumnCount, ColumnDefinitions.Count - newColumnCount);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新子项索引
|
||
var cellPosition = 0;
|
||
var cellsToSkip = new Queue<int>();
|
||
foreach (UIElement child in Children)
|
||
{
|
||
if (IsAutoIndexing && GetAutoIndex(child) == true)
|
||
{
|
||
if (cellsToSkip.Any() && cellsToSkip.Peek() == cellPosition)
|
||
{
|
||
cellsToSkip.Dequeue();
|
||
cellPosition += 1;
|
||
}
|
||
|
||
if (!isVertical) // 水平(默认)
|
||
{
|
||
var rowIndex = cellPosition / ColumnDefinitions.Count;
|
||
SetRow(child, rowIndex);
|
||
|
||
var columnIndex = cellPosition % ColumnDefinitions.Count;
|
||
SetColumn(child, columnIndex);
|
||
|
||
var rowSpan = GetRowSpan(child);
|
||
if (rowSpan > 1)
|
||
{
|
||
Enumerable
|
||
.Range(1, rowSpan)
|
||
.ToList()
|
||
.ForEach(x => cellsToSkip.Enqueue(cellPosition + ColumnDefinitions.Count * x));
|
||
}
|
||
|
||
var overrideRowHeight = GetRowHeightOverride(child);
|
||
if (overrideRowHeight != null)
|
||
{
|
||
RowDefinitions[rowIndex].Height = overrideRowHeight.Value;
|
||
}
|
||
|
||
var overrideColumnWidth = GetColumnWidthOverride(child);
|
||
if (overrideColumnWidth != null)
|
||
{
|
||
ColumnDefinitions[columnIndex].Width = overrideColumnWidth.Value;
|
||
}
|
||
|
||
cellPosition += GetColumnSpan(child);
|
||
}
|
||
else
|
||
{
|
||
var rowIndex = cellPosition % RowDefinitions.Count;
|
||
SetRow(child, rowIndex);
|
||
|
||
var columnIndex = cellPosition / RowDefinitions.Count;
|
||
SetColumn(child, columnIndex);
|
||
|
||
var columnSpan = GetColumnSpan(child);
|
||
if (columnSpan > 1)
|
||
{
|
||
Enumerable
|
||
.Range(1, columnSpan)
|
||
.ToList()
|
||
.ForEach(x => cellsToSkip.Enqueue(cellPosition + RowDefinitions.Count * x));
|
||
}
|
||
|
||
var overrideRowHeight = GetRowHeightOverride(child);
|
||
if (overrideRowHeight != null)
|
||
{
|
||
RowDefinitions[rowIndex].Height = overrideRowHeight.Value;
|
||
}
|
||
|
||
var overrideColumnWidth = GetColumnWidthOverride(child);
|
||
if (overrideColumnWidth != null)
|
||
{
|
||
ColumnDefinitions[columnIndex].Width = overrideColumnWidth.Value;
|
||
}
|
||
|
||
cellPosition += GetRowSpan(child);
|
||
}
|
||
}
|
||
|
||
// 设置默认页边距和对齐方式
|
||
ApplyChildDefaultLayout(child);
|
||
}
|
||
}
|
||
}
|
||
|
||
#region 附加属性
|
||
// 附加属性 AutoIndex
|
||
public static readonly DependencyProperty AutoIndexProperty = DependencyProperty.RegisterAttached(
|
||
"AutoIndex",
|
||
typeof(bool),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsParentMeasure)
|
||
);
|
||
|
||
public static readonly DependencyProperty ColumnWidthOverrideProperty = DependencyProperty.RegisterAttached(
|
||
"ColumnWidthOverride",
|
||
typeof(GridLength?),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
default(GridLength?),
|
||
FrameworkPropertyMetadataOptions.AffectsParentMeasure
|
||
| FrameworkPropertyMetadataOptions.AffectsArrange
|
||
| FrameworkPropertyMetadataOptions.AffectsMeasure
|
||
)
|
||
);
|
||
|
||
// RowHeight 重载附加属性
|
||
|
||
public static readonly DependencyProperty RowHeightOverrideProperty = DependencyProperty.RegisterAttached(
|
||
"RowHeightOverride",
|
||
typeof(GridLength?),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
default(GridLength?),
|
||
FrameworkPropertyMetadataOptions.AffectsParentMeasure
|
||
| FrameworkPropertyMetadataOptions.AffectsArrange
|
||
| FrameworkPropertyMetadataOptions.AffectsMeasure
|
||
)
|
||
);
|
||
|
||
public static bool GetAutoIndex(DependencyObject element)
|
||
{
|
||
return (bool)element.GetValue(AutoIndexProperty);
|
||
}
|
||
|
||
public static GridLength? GetColumnWidthOverride(DependencyObject element)
|
||
{
|
||
return (GridLength?)element.GetValue(ColumnWidthOverrideProperty);
|
||
}
|
||
|
||
public static GridLength? GetRowHeightOverride(DependencyObject element)
|
||
{
|
||
return (GridLength?)element.GetValue(RowHeightOverrideProperty);
|
||
}
|
||
|
||
public static void SetAutoIndex(DependencyObject element, bool value)
|
||
{
|
||
element.SetValue(AutoIndexProperty, value);
|
||
}
|
||
|
||
public static void SetColumnWidthOverride(DependencyObject element, GridLength? value)
|
||
{
|
||
element.SetValue(ColumnWidthOverrideProperty, value);
|
||
}
|
||
|
||
public static void SetRowHeightOverride(DependencyObject element, GridLength? value)
|
||
{
|
||
element.SetValue(RowHeightOverrideProperty, value);
|
||
}
|
||
#endregion
|
||
|
||
#region 依赖属性
|
||
|
||
public static readonly DependencyProperty ChildHorizontalAlignmentProperty = DependencyProperty.Register(
|
||
nameof(ChildHorizontalAlignment),
|
||
typeof(HorizontalAlignment?),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
null,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnChildHorizontalAlignmentChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 改变【子水平对齐方式】时调用。
|
||
/// </summary>
|
||
private static void OnChildHorizontalAlignmentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is AutoGrid grid)
|
||
{
|
||
foreach (UIElement child in grid.Children)
|
||
{
|
||
if (grid.ChildHorizontalAlignment.HasValue)
|
||
child.SetValue(HorizontalAlignmentProperty, grid.ChildHorizontalAlignment);
|
||
else
|
||
child.SetValue(HorizontalAlignmentProperty, DependencyProperty.UnsetValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
public static readonly DependencyProperty ChildMarginProperty = DependencyProperty.Register(
|
||
nameof(ChildMargin),
|
||
typeof(Thickness?),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
null,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnChildMarginChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 【子布局更改】时调用。
|
||
/// </summary>
|
||
private static void OnChildMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is AutoGrid grid)
|
||
{
|
||
foreach (UIElement child in grid.Children)
|
||
{
|
||
if (grid.ChildMargin.HasValue)
|
||
child.SetValue(MarginProperty, grid.ChildMargin);
|
||
else
|
||
child.SetValue(MarginProperty, DependencyProperty.UnsetValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
public static readonly DependencyProperty ChildVerticalAlignmentProperty = DependencyProperty.Register(
|
||
nameof(ChildVerticalAlignment),
|
||
typeof(VerticalAlignment?),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
null,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnChildVerticalAlignmentChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 改变【子垂直排列方式】时调用。
|
||
/// </summary>
|
||
private static void OnChildVerticalAlignmentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is AutoGrid grid)
|
||
{
|
||
foreach (UIElement child in grid.Children)
|
||
{
|
||
if (grid.ChildVerticalAlignment.HasValue)
|
||
child.SetValue(VerticalAlignmentProperty, grid.ChildVerticalAlignment);
|
||
else
|
||
child.SetValue(VerticalAlignmentProperty, DependencyProperty.UnsetValue);
|
||
}
|
||
}
|
||
}
|
||
|
||
public static readonly DependencyProperty IsAutoIndexingProperty = DependencyProperty.Register(
|
||
nameof(IsAutoIndexing),
|
||
typeof(bool),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
true,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnPropertyChanged)
|
||
)
|
||
);
|
||
|
||
public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
|
||
nameof(Orientation),
|
||
typeof(Orientation),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
Orientation.Horizontal,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnPropertyChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 处理重绘属性更改事件
|
||
/// </summary>
|
||
static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
((AutoGrid)d).shouldReindex = true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置子项水平对齐方式。
|
||
/// </summary>
|
||
/// <value>子项水平对齐。</value>
|
||
[Category("Layout"), Description("预设所有子控件的水平对齐方式")]
|
||
public HorizontalAlignment? ChildHorizontalAlignment
|
||
{
|
||
get { return (HorizontalAlignment?)GetValue(ChildHorizontalAlignmentProperty); }
|
||
set { SetValue(ChildHorizontalAlignmentProperty, value); }
|
||
}
|
||
|
||
///// <summary>
|
||
///// 行数
|
||
///// </summary>
|
||
//public int RowCount
|
||
//{
|
||
// get { return (int)GetValue(RowCountProperty); }
|
||
// set { SetValue(RowCountProperty, value); }
|
||
//}
|
||
|
||
//// Using a DependencyProperty as the backing store for RowCount. This enables animation, styling, binding, etc...
|
||
//public static readonly DependencyProperty RowCountProperty = DependencyProperty.Register(
|
||
// nameof(RowCount),
|
||
// typeof(int),
|
||
// typeof(AutoGrid),
|
||
// new PropertyMetadata(1, new PropertyChangedCallback(OnRowCountChanged))
|
||
//);
|
||
|
||
///// <summary>
|
||
///// 处理行数修改事件
|
||
///// </summary>
|
||
//private static void OnRowCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
//{
|
||
// if (d is AutoGrid grid)
|
||
// {
|
||
// if ((int)e.NewValue < 0 || grid.Rows != string.Empty)
|
||
// {
|
||
// return;
|
||
// }
|
||
// // 查找现有行以获取高度
|
||
// var height = GridLength.Auto;
|
||
// //var height = new GridLength(1, GridUnitType.Star);
|
||
// if (grid.RowDefinitions.Count > 0)
|
||
// height = grid.RowDefinitions[0].Height;
|
||
|
||
// // 清理和重建
|
||
// grid.RowDefinitions.Clear();
|
||
// for (var i = 0; i < (int)e.NewValue; i++)
|
||
// grid.RowDefinitions.Add(new RowDefinition() { Height = height });
|
||
// }
|
||
//}
|
||
|
||
///// <summary>
|
||
///// 列数量
|
||
///// </summary>
|
||
//public int ColumnCount
|
||
//{
|
||
// get { return (int)GetValue(ColumnCountProperty); }
|
||
// set { SetValue(ColumnCountProperty, value); }
|
||
//}
|
||
|
||
//// Using a DependencyProperty as the backing store for RowCount. This enables animation, styling, binding, etc...
|
||
//public static readonly DependencyProperty ColumnCountProperty = DependencyProperty.Register(
|
||
// nameof(ColumnCount),
|
||
// typeof(int),
|
||
// typeof(AutoGrid),
|
||
// new PropertyMetadata(1, new PropertyChangedCallback(OnColumnCountChanged))
|
||
//);
|
||
|
||
///// <summary>
|
||
///// 处理列数更改事件
|
||
///// </summary>
|
||
//private static void OnColumnCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
//{
|
||
// if (d is AutoGrid grid)
|
||
// {
|
||
// if ((int)e.NewValue < 0 || grid.Columns != string.Empty)
|
||
// {
|
||
// return;
|
||
// }
|
||
|
||
// // 查找高度的现有列定义
|
||
// var width = GridLength.Auto;
|
||
// //均分
|
||
// //var width = new GridLength(1, GridUnitType.Star);
|
||
// if (grid.ColumnDefinitions.Count > 0)
|
||
// width = grid.ColumnDefinitions[0].Width;
|
||
|
||
// // 清理和重建
|
||
// grid.ColumnDefinitions.Clear();
|
||
// for (var i = 0; i < (int)e.NewValue; i++)
|
||
// grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = width });
|
||
// }
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 获取或设置子项边距。
|
||
/// </summary>
|
||
/// <value>子项边距</value>
|
||
[
|
||
Category("Layout"),
|
||
Description("预设所有子控件的边距")
|
||
]
|
||
public Thickness? ChildMargin
|
||
{
|
||
get { return (Thickness?)GetValue(ChildMarginProperty); }
|
||
set { SetValue(ChildMarginProperty, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置子项垂直对齐方式。
|
||
/// </summary>
|
||
/// <value>子项垂直排列。</value>
|
||
[Category("Layout"), Description("预设所有子控件的垂直对齐方式")]
|
||
public VerticalAlignment? ChildVerticalAlignment
|
||
{
|
||
get { return (VerticalAlignment?)GetValue(ChildVerticalAlignmentProperty); }
|
||
set { SetValue(ChildVerticalAlignmentProperty, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置列,优先级高于ColumnCount
|
||
/// </summary>
|
||
[Category("Layout"), Description("使用逗号分隔的网格长度符号定义所有列")]
|
||
public string Columns
|
||
{
|
||
get { return (string)GetValue(ColumnsProperty); }
|
||
set { SetValue(ColumnsProperty, value); }
|
||
}
|
||
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register(
|
||
nameof(Columns),
|
||
typeof(string),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
"",
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnColumnsChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 处理列更改事件
|
||
/// </summary>
|
||
private static void OnColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if ((string)e.NewValue == string.Empty)
|
||
{
|
||
return;
|
||
}
|
||
if (d is AutoGrid grid)
|
||
{
|
||
grid.ColumnDefinitions.Clear();
|
||
|
||
var defs = Parse((string)e.NewValue);
|
||
foreach (var def in defs)
|
||
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = def });
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置固定列宽,默认自动
|
||
/// </summary>
|
||
[Category("Layout"), Description("预设使用 ColumnCount 属性设置的所有列的宽度")]
|
||
public GridLength ColumnWidth
|
||
{
|
||
get { return (GridLength)GetValue(ColumnWidthProperty); }
|
||
set { SetValue(ColumnWidthProperty, value); }
|
||
}
|
||
|
||
public static readonly DependencyProperty ColumnWidthProperty = DependencyProperty.Register(
|
||
nameof(ColumnWidth),
|
||
typeof(GridLength),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
GridLength.Auto,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnFixedColumnWidthChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 处理固定列宽更改事件
|
||
/// </summary>
|
||
private static void OnFixedColumnWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is AutoGrid grid)
|
||
{
|
||
// 如果缺少,添加默认列
|
||
if (grid.ColumnDefinitions.Count == 0)
|
||
grid.ColumnDefinitions.Add(new ColumnDefinition());
|
||
|
||
// 将所有现有列设置为该宽度
|
||
for (var i = 0; i < grid.ColumnDefinitions.Count; i++)
|
||
grid.ColumnDefinitions[i].Width = (GridLength)e.NewValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置表示是否自动索引子项的值。
|
||
/// <remarks>
|
||
/// 默认值为<c>true</c>.
|
||
/// 请注意,如果子项已有索引,将此属性设置为 <c>false</c> 将不会移除其索引。
|
||
/// </remarks>
|
||
/// </summary>
|
||
[Category("Layout"), Description("设置为 false 则禁用自动布局功能")]
|
||
public bool IsAutoIndexing
|
||
{
|
||
get { return (bool)GetValue(IsAutoIndexingProperty); }
|
||
set { SetValue(IsAutoIndexingProperty, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置方向。
|
||
/// <remarks>默认值为垂直。</remarks>
|
||
/// </summary>
|
||
/// <value>定向。</value>
|
||
[Category("Layout"), Description("定义自动布局的方向性。列优先布局使用垂直方向,行优先布局使用水平方向。")]
|
||
public Orientation Orientation
|
||
{
|
||
get { return (Orientation)GetValue(OrientationProperty); }
|
||
set { SetValue(OrientationProperty, value); }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置固定行高
|
||
/// </summary>
|
||
[Category("Layout"), Description("预设使用行数属性设置的所有行的高度")]
|
||
public GridLength RowHeight
|
||
{
|
||
get { return (GridLength)GetValue(RowHeightProperty); }
|
||
set { SetValue(RowHeightProperty, value); }
|
||
}
|
||
public static readonly DependencyProperty RowHeightProperty = DependencyProperty.Register(
|
||
nameof(RowHeight),
|
||
typeof(GridLength),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
GridLength.Auto,
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnFixedRowHeightChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 处理固定行高更改事件
|
||
/// </summary>
|
||
private static void OnFixedRowHeightChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if (d is AutoGrid grid)
|
||
{
|
||
// 如果缺失,则添加默认行
|
||
if (grid.RowDefinitions.Count == 0)
|
||
grid.RowDefinitions.Add(new RowDefinition());
|
||
|
||
// 将所有现有行设置为该高度
|
||
for (var i = 0; i < grid.RowDefinitions.Count; i++)
|
||
grid.RowDefinitions[i].Height = (GridLength)e.NewValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取或设置行数,优先级高于RowCount
|
||
/// </summary>
|
||
[Category("Layout"), Description("使用逗号分隔的网格长度符号定义所有行")]
|
||
public string Rows
|
||
{
|
||
get { return (string)GetValue(RowsProperty); }
|
||
set { SetValue(RowsProperty, value); }
|
||
}
|
||
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register(
|
||
nameof(Rows),
|
||
typeof(string),
|
||
typeof(AutoGrid),
|
||
new FrameworkPropertyMetadata(
|
||
"",
|
||
FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange,
|
||
new PropertyChangedCallback(OnRowsChanged)
|
||
)
|
||
);
|
||
|
||
/// <summary>
|
||
/// 处理行修改事件
|
||
/// </summary>
|
||
private static void OnRowsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||
{
|
||
if ((string)e.NewValue == string.Empty)
|
||
{
|
||
return;
|
||
}
|
||
if (d is AutoGrid grid)
|
||
{
|
||
grid.RowDefinitions.Clear();
|
||
|
||
var defs = Parse((string)e.NewValue);
|
||
foreach (var def in defs)
|
||
grid.RowDefinitions.Add(new RowDefinition() { Height = def });
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
|
||
#region 重写
|
||
|
||
/// <summary>
|
||
/// 测量 <see cref="T:System.Windows.Controls.Grid"/> 的子网格,以便在 <see cref="M:ArrangeOverride"/> 传递期间整理它们。
|
||
/// </summary>
|
||
/// <param name="constraint">表示不应超过的上限大小。</param>
|
||
/// <returns>
|
||
/// <see cref="Size"/> 表示安排子内容所需的大小。
|
||
/// </returns>
|
||
protected override Size MeasureOverride(Size constraint)
|
||
{
|
||
PerformLayout();
|
||
return base.MeasureOverride(constraint);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当 <see cref="Grid"/> 元素的可视化子元素发生变化时调用。
|
||
/// <remarks>用于标记网格已更改子项。</remarks>
|
||
/// </summary>
|
||
/// <param name="visualAdded">标识添加的Visual子项。</param>
|
||
/// <param name="visualRemoved">标识移除的Visual子项。</param>
|
||
protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
|
||
{
|
||
shouldReindex = true;
|
||
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
|
||
}
|
||
#endregion
|
||
}
|