我创建了一个继承自WPF 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
但没有任何反应;我错过了什么或者由于某些错误而发生这种情况?
Update :
澄清一下,说我的画布有 width
, height
为100,100 . 现在,如果我使用 Canvas.SetLeft(myControl, 200)
移动一个控件(已在画布中添加),那么它将移动到默认情况下不可见的位置,滚动条也是禁用,所以没有办法看到那个控件 .
现在,如果我向Canvas添加另一个控件,ScrollBars会正确显示,我可以通过滚动查看上一个控件 .
3 回答
您是否在自定义画布中覆盖了MeasureOverride? Canvas将始终报告DesiredSize(0,0),因此ScrollViewer永远不会认为它需要滚动 .
请参阅this StackOverflow answer,建议使用Grid而不是Canvas并使用Margin属性进行定位 . Grid将根据子节点的大小和位置报告其大小,因此ScrollViewer将知道它需要滚动 .
更新:
ScrollViewer会根据需要为其子项提供更大的大小,并且只有在子项大于ScrollViewer时才需要滚动 . 为了让它正确滚动,您需要报告一个足够大的DesiredSize,以包含所有子控件 . 你可以通过重写MeasureOverride来做到这一点:
但是,更简单的解决方案是利用Grid类已经如此测量的事实 . 您可以使用子元素的Margin属性来精确定位它们,而不是Canvas.Left和Canvas.Top属性 . 如果你现在在做
对于Canvas中的项目,您可以改为
将它定位在单格网格中的相同位置 .
Quartermeister的回答帮助我解决了这个问题 .
我必须在每次操作后显式使用 base.InvalidateMeasure() 来刷新画布并使滚动条可见 .
Akjoshi,
它必须是一个bug . 下次画布变为隐藏的某个地方时,在其上运行Snoop,并检查它的位置 . 确保检查以下画布属性:
ActualWidth
,ActualHeight
,Opacity
,Visibility