我创建了一个继承自 WPF Canvas
的自定义 Canvas 控件。我在主窗口中这样使用它-
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<RTD:RTDesignerCanvas
Margin="5"
Background="White"
x:Name="canvas1"
Focusable="True"
AllowDrop="True">
</RTD:RTDesignerCanvas>
</ScrollViewer>
一切正常,但是当我尝试像这样设置控件的位置时
Canvas.SetTop(item, 200);
滚动条不可见,控件隐藏在某处。有趣的是,如果我向它添加另一个控件,滚动条是可见的,我可以向下滚动以查看上一个控件。
我尝试使用
base.InvalidateVisual();
base.UpdateLayout();
base.InvalidateArrange();
在更改项目 Top
或 Left
但没有任何反应;是我遗漏了什么还是由于某些错误而发生这种情况?
更新:
澄清一下,假设我有一个 Canvas ,其 width
、height
为 100、100。现在,如果我使用 移动控件(已添加到 Canvas 中) >Canvas.SetLeft(myControl, 200)
然后它会移动到一个默认不可见的位置并且滚动条也被禁用,所以没有办法看到那个控件。
现在如果我向 Canvas 添加另一个控件,ScrollBars 会正确显示,并且我可以通过滚动看到之前的控件。
最佳答案
您是否覆盖了 MeasureOverride在您的自定义 Canvas 中? Canvas 将始终报告 (0, 0) 的 DesiredSize,因此 ScrollViewer 永远不会认为它需要滚动。
见 this StackOverflow answer这建议使用 Grid 而不是 Canvas 并使用 Margin 属性进行定位。 Grid 将根据其子项的大小和位置报告其大小,因此 ScrollViewer 将知道它需要滚动。
更新:
ScrollViewer 会根据它的要求给它的 child 询问多大的尺寸,并且只有当 child 比 ScrollViewer 大时才需要滚动。为了让它正确滚动,您需要报告一个足够大以包含所有子控件的 DesiredSize。您可以通过像这样覆盖 MeasureOverride 来做到这一点:
protected override Size MeasureOverride(Size constraint)
{
base.MeasureOverride(constraint);
var desiredSize = new Size();
foreach (UIElement child in Children)
{
desiredSize = new Size(
Math.Max(desiredSize.Width, GetLeft(child) + child.DesiredSize.Width),
Math.Max(desiredSize.Height, GetTop(child) + child.DesiredSize.Height));
}
return desiredSize;
}
然而,一个更简单的解决方案是利用 Grid 类已经像这样进行测量的事实。您可以使用子元素的 Margin 属性来准确定位它们,而不是使用 Canvas.Left 和 Canvas.Top 属性。如果你目前正在做
Canvas.SetLeft(item, 100);
Canvas.SetTop(item, 200);
对于 Canvas 中的项目,您可以改为这样做
item.Margin = new Thickness(100, 200, 0, 0);
将其放置在单格网格内的相同位置。
关于.net - 更改 Canvas 内控件的位置后,滚动条不可见,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3061400/