控件功能
根据自定义行和列,快速进行排列,能够进行自定义控件间距离,减少元素进行定义间距,同时能更好的维护界面排序。
代码部分
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;namespace WPFApp
{public class AutoGrid : Grid{/// <summary>/// 列定义 例如: "100,*,100" "100 * 100"/// </summary>[Category("Layout")]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 PropertyMetadata("", ColumnsChanged));/// <summary>/// 行定义 例如: "100,*,100" "100 * 100" /// </summary>[Category("Layout")]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 PropertyMetadata("", RowsChange));/// <summary>/// 排列方式/// </summary>[Category("Layout")]public Orientation Orientation{get { return (Orientation)GetValue(OrientationProperty); }set { SetValue(OrientationProperty, value); }}public static readonly DependencyProperty OrientationProperty =DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(AutoGrid), new PropertyMetadata(Orientation.Horizontal));/// <summary>/// 元素之间Margin/// </summary>[Category("Layout")]public Thickness? ChildMargin{get { return (Thickness?)GetValue(ChildMarginProperty); }set { SetValue(ChildMarginProperty, value); }}public static readonly DependencyProperty ChildMarginProperty =
DependencyProperty.Register(nameof(ChildMargin), typeof(Thickness?), typeof(AutoGrid), new PropertyMetadata((Thickness?)null, OnChildMarginChanged));/// <summary>/// 移除多余的元素/// </summary>public bool IsRemoveEleme { get; set; } = true;private static void OnChildMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var grid = d as AutoGrid;foreach (UIElement child in grid.Children){if (grid.ChildMargin.HasValue)child.SetValue(FrameworkElement.MarginProperty, grid.ChildMargin);elsechild.SetValue(FrameworkElement.MarginProperty, DependencyProperty.UnsetValue);}}protected override Size MeasureOverride(Size constraint){PerformLayout();return base.MeasureOverride(constraint);}private void PerformLayout(){int colCount = this.ColumnDefinitions.Count;int rowCount = this.RowDefinitions.Count;if (colCount == 0 || rowCount == 0) return;var position = 0;foreach (UIElement child in Children){var childIsCollapsed = child.Visibility == Visibility.Collapsed;if (childIsCollapsed) continue;if (this.Orientation == Orientation.Horizontal){//从左往右,再从上往下var row = Clamp(position / colCount, rowCount - 1);var col = Clamp(position % colCount, colCount - 1);Grid.SetRow(child, row);Grid.SetColumn(child, col);Grid.SetRowSpan(child, 1);position += Grid.GetColumnSpan(child);}else{//从上往下,再从左往右var row = Clamp(position % rowCount, rowCount - 1);var col = Clamp(position / rowCount, colCount - 1);Grid.SetRow(child, row);Grid.SetColumn(child, col);Grid.SetColumnSpan(child, 1);position += Grid.GetRowSpan(child);}//设置Marginif (ChildMargin.HasValue){child.SetValue(FrameworkElement.MarginProperty, ChildMargin);}else{child.SetValue(FrameworkElement.MarginProperty, DependencyProperty.UnsetValue);}}//移除无法分配的元素if (IsRemoveEleme && Children.Count > colCount * rowCount){Children.RemoveRange(colCount * rowCount, Children.Count - colCount * rowCount);}}private int Clamp(int value, int max){return (value > max) ? max : value;}private static void RowsChange(DependencyObject d, DependencyPropertyChangedEventArgs e){if (string.IsNullOrEmpty((string)e.NewValue)) return;var grid = (AutoGrid)d;grid.RowDefinitions.Clear();GridLength[] defs = GridLengthParse((string)e.NewValue);foreach (var def in defs){grid.RowDefinitions.Add(new RowDefinition(){Height = def});}}private static void ColumnsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){if (string.IsNullOrEmpty((string)e.NewValue)) return;var grid = (AutoGrid)d;grid.ColumnDefinitions.Clear();GridLength[] defs = GridLengthParse((string)e.NewValue);foreach (var def in defs){grid.ColumnDefinitions.Add(new ColumnDefinition(){Width = def});}}public static GridLength[] GridLengthParse(string text){string[] tokens = text.Split([' ', ','], StringSplitOptions.RemoveEmptyEntries);GridLength[] defineResult = new GridLength[tokens.Length];for (int i = 0; i < tokens.Count(); i++){string curStr = tokens[i];double value = 0.0;//Starif (curStr.Contains('*')){if (!double.TryParse(curStr.Replace("*", ""), out value)){value = 1.0;}defineResult[i] = new GridLength(value, GridUnitType.Star);}//Pixelif (double.TryParse(curStr, out value)){defineResult[i] = new GridLength(value, GridUnitType.Pixel);continue;}//AutodefineResult[i] = GridLength.Auto;}return defineResult;}}
}
使用示例
<Windowx:Class="WPFApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="clr-namespace:WPFApp"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="800"Height="450"mc:Ignorable="d"><Window.DataContext><local:MainWindowViewModel /></Window.DataContext><local:AutoGridChildMargin="10,10,0,0"Columns="100 200 300 400"Orientation="Horizontal"Rows="200 *"><TextBlock Text="1" /><TextBlock Text="2" /><TextBlock Text="3" /><TextBlock Text="4" /><TextBlock Text="5" /><TextBlock Text="6" /><TextBlock Text="7" /><TextBlock Text="8" /><TextBlock Text="9" /><TextBlock Text="10" /><TextBlock Text="11" /><TextBlock Text="12" /></local:AutoGrid>
</Window>