[英]ScrollViewer doesn't scroll for custom panel
我正在制作自己的自定义面板,当内容不适合可用空间时,该面板应该垂直滚动,因此我将其放在ScrollViewer中。 现在,当内部面板大于ScrollViewer本身时,我无法使ScrollViewer激活滚动条。
permille函数具有附加的属性,该属性指示必须将孩子的大小与可用大小(不滚动)(又称为ViewPort)进行比较。 由于在MeasureOverride中传递的大小会无限传递,所以我认为我无法在其中使用permille函数。 这就是为什么我在ArrangeOverride中衡量我的孩子们的原因(我猜这不是最佳实践),但是那样,scrollviewer不会滚动。
我该如何工作?
我的XAML代码:
<ScrollViewer>
<controls:TilePanel x:Name="TilePanel" PreviewMouseLeftButtonDown="TilePanel_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonUp="TilePanel_PreviewMouseLeftButtonUp"
PreviewMouseMove="TilePanel_PreviewMouseMove" DragEnter="TilePanel_DragEnter" Drop="TilePanel_Drop" AllowDrop="True" />
</ScrollViewer>
我的自定义面板类:
/// <summary>
/// A Panel Showing Tiles
/// </summary>
public class TilePanel : PermillePanel
{
public TilePanel()
{
}
protected override Size MeasureOverride(Size constraint)
{
//here constraint width or height can be infinite.
//as tiles are a permille of that height, they too can be infinite after measuring
//this is unwanted behavior, so we measure in the ArrangeOverride method
if (constraint.Width == double.PositiveInfinity)
{
return new Size(0, constraint.Height);
}
else if (constraint.Height == double.PositiveInfinity)
{
return new Size(constraint.Width, 0);
}
else
{
return constraint;
}
}
protected override Size ArrangeOverride(Size arrangeSize)
{
//return base.ArrangeOverride(arrangeSize);
foreach (FrameworkElement child in InternalChildren)
{
Size availableSize = new Size();
//set the width and height for the child
availableSize.Width = arrangeSize.Width * TilePanel.GetHorizontalPermille(child) / 1000;
availableSize.Height = arrangeSize.Height * TilePanel.GetVerticalPermille(child) / 1000;
child.Measure(availableSize);
}
// arrange the children on the panel
// fill lines horizontally, when we reach the end of the current line, continue to the next line
Size newSize = new Size(arrangeSize.Width, arrangeSize.Height);
double xlocation = 0;
double ylocation = 0;
double ystep = 0;
double maxYvalue = 0;
foreach (FrameworkElement child in InternalChildren)
{
double endxlocation = xlocation + child.DesiredSize.Width;
double constrainedWidth = arrangeSize.Width * TilePanel.GetHorizontalPermille(child) / 1000;
double constrainedHeight = arrangeSize.Height * TilePanel.GetVerticalPermille(child) / 1000;
if (TilePanel.GetVerticalPermille(child) != 0 && TilePanel.GetHorizontalPermille(child) != 0)
{
//horizontal overflow -> next line
if (endxlocation >= this.DesiredSize.Width *1.01)
{
ylocation += ystep;
xlocation = 0;
}
}
Rect rect = new Rect(xlocation, ylocation, constrainedWidth, constrainedHeight);
child.Arrange(rect);
xlocation += constrainedWidth;
ystep = Math.Max(ystep, constrainedHeight);
maxYvalue = Math.Max(maxYvalue, ystep + constrainedHeight);
}
if (maxYvalue > newSize.Height)
{
newSize.Height = maxYvalue;
}
return newSize;
}
}
从ArrangeOverride()
调用Measure()
会引起问题。 框架会检测到这一点并强制进行重新测量。 在MeasureOverride()
设置一个跟踪点,我敢打赌,即使布局没有更改1 ,它也会一遍又一遍地被调用。
如果绝对必须从ArrangeOverride()
调用Measure()
,则需要有条件地这样做,以便仅在自上次调用Measure()
以来可用大小实际发生变化时才强制重新Measure()
。 然后,在布局无效时,您将有效地获得两次测量+布置遍,而不是一次。 但是,这种方法很不明智,我建议您坚持仅在MeasureOverride()
测量的最佳实践。
1有趣的是,尽管布局中存在明显的“无限循环”,您的UI仍可能响应输入。
如果要在ScrollViewer
使用自定义Panel
则必须添加执行实际滚动的代码。 您可以通过在自定义Panel
实现IScrollInfo
接口来实现。
您可以在Tech Pro网站上的WPF教程-实现IScrollInfo页面中找到说明该界面并提供示例代码实现的教程 。 这是一个相当简单的过程,看起来像这样:
public void LineDown() { SetVerticalOffset(VerticalOffset + LineSize); }
public void LineUp() { SetVerticalOffset(VerticalOffset - LineSize); }
public void MouseWheelDown() { SetVerticalOffset(VerticalOffset + WheelSize); }
public void MouseWheelUp() { SetVerticalOffset(VerticalOffset - WheelSize); }
public void PageDown() { SetVerticalOffset(VerticalOffset + ViewportHeight); }
public void PageUp() { SetVerticalOffset(VerticalOffset - ViewportHeight); }
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.