![]() // 自定义一个从左至右排列、从上往下换行的面板,并且提供一个附加属性可以指示在哪个子元素前换行 public class MyWrapPanel : Panel { // 定义一个指示在哪个子元素前换行的附加属性 public static readonly DependencyProperty LineBreakBeforeProperty; static MyWrapPanel() { var metadata = new FrameworkPropertyMetadata { AffectsMeasure = true, AffectsArrange = true }; LineBreakBeforeProperty = DependencyProperty.RegisterAttached("LineBreakBefore", typeof(bool), typeof(MyWrapPanel), metadata); } public static void SetLineBreakBefore(UIElement element, bool value) { element.SetValue(LineBreakBeforeProperty, value); } public static bool GetLineBreakBefore(UIElement element) { return (bool)element.GetValue(LineBreakBeforeProperty); } protected override Size MeasureOverride(Size availableSize) { var totalWidth = 0.0; var totalHeight = 0.0; var rowHeight = 0.0; var rowWidth = 0.0; foreach (UIElement uiElement in this.Children) { uiElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); // 当行宽超过了可用空间的宽度或者子元素设置了换行的附加属性时换行 if (rowWidth + uiElement.DesiredSize.Width >= availableSize.Width || GetLineBreakBefore(uiElement)) { // 面板的总宽度是所有行的最大宽度 totalWidth = Math.Max(totalWidth, rowWidth); // 面板的高度是所有行的高度之和 totalHeight += rowHeight; // 换行后重置行高和行宽 rowHeight = 0.0; rowWidth = 0.0; } else { // 每一行的宽度是所有子元素宽度之和 rowWidth += uiElement.DesiredSize.Width; // 每一行的高度都是这一行中所有子元素的最大高度 rowHeight = Math.Max(rowHeight, uiElement.DesiredSize.Height); } } // 加上最后一行的高度 totalHeight += rowHeight; return new Size(totalWidth, totalHeight); } protected override Size ArrangeOverride(Size finalSize) { var x = 0.0; var y = 0.0; var rowHeight = 0.0; foreach (UIElement uie in this.Children) { // 如果该子元素将要超出边界或者设置了换行,则换一行从头显示 if (x + uie.DesiredSize.Width >= finalSize.Width || GetLineBreakBefore(uie)) { x = 0.0; y += rowHeight; // 重置行高 rowHeight = 0.0; } uie.Arrange(new Rect(x, y, uie.DesiredSize.Width, uie.DesiredSize.Height)); rowHeight = Math.Max(rowHeight, uie.DesiredSize.Height); x = x + uie.DesiredSize.Width; } return finalSize; } }
|
|