【问题标题】:WPF Uniform Grid LayoutWPF统一网格布局
【发布时间】:2026-01-04 11:40:01
【问题描述】:

我对统一网格中的布局有要求。下面是布局

在统一网格中,第二行布局项应从 Right_to_Left 开始(不使用流向)。目前是从 Left_to_Right 开始

当我折叠“Button1”时,布局应该如下所示

谁能帮帮我

【问题讨论】:

    标签: wpf wpf-controls uniformgrid


    【解决方案1】:

    猜你可以通过调整 ArrangeOverride(...) 中的 UniformGrid 来做到这一点

    如果您只是在寻找示例,您可以下载演示 -> Here

    首先,我确实从Here 中找到了一个以垂直方向(按列)布局元素的示例

    因此,使用该解决方案,我可以将 ArrangeOverride(...) 更新为:

    protected override Size ArrangeOverride(Size arrangeSize) {
      var finalRect = new Rect(0.0, 0.0, arrangeSize.Width / _columns, arrangeSize.Height / _rows);
      Double width = finalRect.Width;
      Double maxWidth = arrangeSize.Width;
      finalRect.X += finalRect.Width * FirstColumn;
      int currentRow = 1;
      foreach (UIElement element in InternalChildren) {
        element.Arrange(finalRect);
        if (element.Visibility == Visibility.Collapsed)
          continue;
        if (currentRow % 2 == 0) {
          finalRect.X -= width;
          if (finalRect.X <= -width) {
            ++currentRow;
            finalRect.Y += finalRect.Height;
            finalRect.X = 0;
          }
        } else {
          finalRect.X += width;
          if (finalRect.X >= maxWidth) {
            ++currentRow;
            finalRect.Y += finalRect.Height;
            finalRect.X = maxWidth - width;
          }
        }
      }
      return arrangeSize;
    }
    

    逻辑: 我们几乎在foreach(...) 中检查元素的当前行和每个备用行,通过相应地修改它的 X 偏移量来切换它的水平方向。

    这会得到您正在寻找的行为。

    下面是完整的派生类代码,以防 msdn 链接将来消失:

    public class MyUniformGrid : UniformGrid {
      private int _columns;
      private int _rows;
    
      protected override Size MeasureOverride(Size constraint) {
        UpdateComputedValues();
        var availableSize = new Size(constraint.Width / (_columns), constraint.Height / (_rows));
        double width = 0.0;
        double height = 0.0;
        int num3 = 0;
        int count = base.InternalChildren.Count;
        while (num3 < count) {
          UIElement element = base.InternalChildren[num3];
          element.Measure(availableSize);
          Size desiredSize = element.DesiredSize;
          if (width < desiredSize.Width) {
            width = desiredSize.Width;
          }
          if (height < desiredSize.Height) {
            height = desiredSize.Height;
          }
          num3++;
        }
        return new Size(width * _columns, height * _rows);
      }
    
      private void UpdateComputedValues() {
        _columns = Columns;
        _rows = Rows;
        if (FirstColumn >= _columns) {
          FirstColumn = 0;
        }
    
        if (FirstColumn > 0)
          throw new NotImplementedException("There is no support for seting the FirstColumn (nor the FirstRow).");
        if ((_rows == 0) || (_columns == 0)) {
          int num = 0; // Visible children  
          int num2 = 0;
          int count = base.InternalChildren.Count;
          while (num2 < count) {
            UIElement element = base.InternalChildren[num2];
            if (element.Visibility != Visibility.Collapsed) {
              num++;
            }
            num2++;
          }
          if (num == 0) {
            num = 1;
          }
          if (_rows == 0) {
            if (_columns > 0) {
              _rows = ((num + FirstColumn) + (_columns - 1)) / _columns;
            } else {
              _rows = (int)Math.Sqrt(num);
              if ((_rows * _rows) < num) {
                _rows++;
              }
              _columns = _rows;
            }
          } else if (_columns == 0) {
            _columns = (num + (_rows - 1)) / _rows;
          }
        }
      }
    
      protected override Size ArrangeOverride(Size arrangeSize) {
        var finalRect = new Rect(0.0, 0.0, arrangeSize.Width / _columns, arrangeSize.Height / _rows);
        Double width = finalRect.Width;
        Double maxWidth = arrangeSize.Width;
        finalRect.X += finalRect.Width * FirstColumn;
        int currentRow = 1;
        foreach (UIElement element in InternalChildren) {
          element.Arrange(finalRect);
          if (element.Visibility == Visibility.Collapsed)
            continue;
          if (currentRow % 2 == 0) {
            finalRect.X -= width;
            if (finalRect.X <= -width) {
              ++currentRow;
              finalRect.Y += finalRect.Height;
              finalRect.X = 0;
            }
          } else {
            finalRect.X += width;
            if (finalRect.X >= maxWidth) {
              ++currentRow;
              finalRect.Y += finalRect.Height;
              finalRect.X = maxWidth - width;
            }
          }
        }
        return arrangeSize;
      }
    }
    

    注意:

    此实现目前不适用于UniformGrid.FirstColumn 属性。如果需要,您可以调整覆盖以适应这种情况。

    【讨论】: