基于MaxWidth实现XAML按钮单行/双行自动对齐布局
实现自适应两行均匀布局的方案
方案1:UniformGrid+后台逻辑(简单易实现)
你之前用UniformGrid没达到效果,问题出在没动态切换行数。这个思路是先计算所有按钮的总宽度,超过200就改成两行,否则保持单行,UniformGrid会自动把按钮尽量均匀分配到两行(比如7个按钮就分成4个+3个)。
XAML代码
<Grid MaxWidth="200"> <UniformGrid x:Name="uniformGrid" Columns="Auto" Rows="1" HorizontalAlignment="Left"> <Button Content="1"/> <Button Content="2"/> <Button Content="3"/> <Button Content="4"/> <Button Content="5"/> <Button Content="6"/> <Button Content="7"/> </UniformGrid> </Grid>
后台代码(以MainWindow.xaml.cs为例)
public MainWindow() { InitializeComponent(); Loaded += OnWindowLoaded; SizeChanged += OnWindowSizeChanged; } private void OnWindowLoaded(object sender, RoutedEventArgs e) { AdjustGridRows(); } private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e) { AdjustGridRows(); } private void AdjustGridRows() { double totalBtnWidth = 0; foreach (Button btn in uniformGrid.Children) { btn.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); totalBtnWidth += btn.DesiredSize.Width; } // 总宽度超200就用两行,否则保持单行 uniformGrid.Rows = totalBtnWidth > 200 ? 2 : 1; }
方案2:自定义布局控件(纯XAML可用,无需后台逻辑)
要是不想写后台代码,可以自定义一个布局控件,直接实现你要的自适应逻辑:总宽度≤200时单行排列,超过则自动分成两行并均匀分配按钮数量。
自定义布局类代码
public class TwoRowAutoLayout : Panel { private const double MaxSingleRowWidth = 200; protected override Size MeasureOverride(Size availableSize) { double totalWidth = 0; double maxHeight = 0; foreach (UIElement child in Children) { child.Measure(new Size(double.PositiveInfinity, availableSize.Height)); totalWidth += child.DesiredSize.Width; maxHeight = Math.Max(maxHeight, child.DesiredSize.Height); } if (totalWidth <= MaxSingleRowWidth) { return new Size(totalWidth, maxHeight); } else { int firstRowCount = (int)Math.Ceiling(Children.Count / 2.0); double firstRowWidth = 0; for (int i = 0; i < firstRowCount; i++) { firstRowWidth += Children[i].DesiredSize.Width; } double secondRowWidth = totalWidth - firstRowWidth; return new Size(Math.Max(firstRowWidth, secondRowWidth), maxHeight * 2); } } protected override Size ArrangeOverride(Size finalSize) { double totalWidth = 0; double maxHeight = 0; foreach (UIElement child in Children) { totalWidth += child.DesiredSize.Width; maxHeight = Math.Max(maxHeight, child.DesiredSize.Height); } if (totalWidth <= MaxSingleRowWidth) { double currentX = 0; foreach (UIElement child in Children) { child.Arrange(new Rect(currentX, 0, child.DesiredSize.Width, maxHeight)); currentX += child.DesiredSize.Width; } } else { int firstRowCount = (int)Math.Ceiling(Children.Count / 2.0); double currentX = 0; // 排列第一行 for (int i = 0; i < firstRowCount; i++) { var child = Children[i]; child.Arrange(new Rect(currentX, 0, child.DesiredSize.Width, maxHeight)); currentX += child.DesiredSize.Width; } // 排列第二行 currentX = 0; for (int i = firstRowCount; i < Children.Count; i++) { var child = Children[i]; child.Arrange(new Rect(currentX, maxHeight, child.DesiredSize.Width, maxHeight)); currentX += child.DesiredSize.Width; } } return finalSize; } }
XAML中使用
<!-- 先引用自定义控件的命名空间,比如xmlns:local="clr-namespace:你的项目命名空间" --> <local:TwoRowAutoLayout MaxWidth="200"> <Button Content="1"/> <Button Content="2"/> <Button Content="3"/> <Button Content="4"/> <Button Content="5"/> <Button Content="6"/> <Button Content="7"/> </local:TwoRowAutoLayout>
为啥之前的UniformGrid/WrapPanel没效果?
- UniformGrid:你可能固定了行数,比如设为2的话,不管宽度够不够都会强制分成两行;设为1又不会自动换行,没法实现自适应。
- WrapPanel:它是按当前行剩余空间判断是否换行,比如第一行能放5个就放5个,剩下的丢第二行,不会考虑两行数量均匀,自然达不到你的需求。
内容的提问来源于stack exchange,提问作者Ohad Cohen
相关产品推荐
相关产品推荐

