UWP Custom Panel sized based on the Panel children arranged height

UWP Custom Panel sized based off the Panel Childrens arranged height

我目前正在尝试创建一个类似于 VariableGridView 的控件,但是内容将控制项目高度,而不是使用 Column/Row 跨度预先计算的项目高度和宽度。使用 Column span 决定控件的宽度。您可以找到 WIP 示例 here.

我目前遇到的唯一问题是控件的初始加载。当控件位于 ScrollViewer 中并且它的高度超过 window/parent 的高度时,它不会滚动。见下文:

然而,一旦我调整 window 的大小,滚动就会按预期正常工作。见下文:

可能很难看清,但如果您查看右侧滚动条较暗的部分,您会发现它在初始加载时未正确调整自身大小。

我怀疑我在控制 MeasureOverride 方法中犯了一个错误,但是我看不出我做错了什么:

 protected override Size MeasureOverride(Size availableSize) {
   // Need to use this method LimitUnboundedSize as when within a 
   // ScrollViewer an infinite height is supplied within the availableSize
   var desiredSize = LimitUnboundedSize(availableSize);
   UpdateColumnOffsets();
   foreach (var child in Children) {
     child.Measure(desiredSize);
   }
   return desiredSize;
 }

 private Size LimitUnboundedSize(Size input) {
   if (Double.IsInfinity(input.Height)) {
     var scrollViewer = this.FindAscendant<ScrollViewer>();
     var contentHeight = scrollViewer.ViewportHeight.Equals(0)
       ?  Window.Current.Bounds.Height : scrollViewer.ViewportHeight;
     input.Height = (contentHeight >= GetMaxOffset ? contentHeight : 
       GetMaxOffset);
   }
   return input;
 }

在设置控件大小时,如何计算项目将占用的高度?

我能够解决我自己的问题。我需要在安排之前弄清楚我的牌的位置。这样将计算 columnOffsets,我可以将面板的高度基于最大列偏移量。

我还没有更新 github 存储库,但这里是需要更新才能正常工作的代码:

protected override Size ArrangeOverride(Size finalSize) {
  foreach (var child in Children) {
    var resizable = child as IArrangeable;
    resizable?.Arrange(pointDictionary.GetValueOrDefault(resizable.Card));
  }
  return finalSize;
}

private double GetMaxOffset {
  get { return columnOffsetY.Max(); }
}

protected override Size MeasureOverride(Size availableSize) {
  var desiredSize = availableSize;
  UpdateColumnOffsets();
  foreach (var child in Children) {
    child.Measure(desiredSize);
    CreateOffsetCache(child);
  }

  if (Double.IsPositiveInfinity(desiredSize.Height))
    desiredSize.Height = GetMaxOffset;

  return desiredSize;

}

private Dictionary<Card, Point> pointDictionary;

private void CreateOffsetCache(UIElement child) {
  var arrangeable = child as IArrangeable;
  if (arrangeable == null) return;
  var card = arrangeable.Card;
  var useColumnOffset = columnOffsetY[card.Column] < columnOffsetY[card.Column + card.ColumnSpan - 1] 
    ? columnOffsetY[card.Column + card.ColumnSpan - 1] : columnOffsetY[card.Column];
  var point = new Point(columnOffsetX[card.Column], useColumnOffset);
  pointDictionary[card] = point;
  SetColumnOffsetY(card.Column, card.ColumnSpan, child.DesiredSize.Height);
}