[ScrollBar在更改画布内部控件的位置后不可见

问题描述 投票:3回答:3

我创建了一个自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();

更改项目TopLeft之后,什么也没有发生;我是否缺少某些东西,或者由于某些错误而发生了这种情况?

更新

澄清一下,假设我有一个画布,其widthheight为100、100。现在如果我使用Canvas.SetLeft(myControl, 200)移动控件(已经添加到画布中),那么它将移动到一个不默认情况下可见,并且滚动条也被禁用,因此无法看到该控件。

现在,如果我向Canvas添加另一个控件,则滚动条会正确显示,并且可以通过滚动看到以前的控件。

.net wpf canvas custom-controls scrollviewer
3个回答
8
投票

您是否在自定义画布中覆盖了MeasureOverride? Canvas将始终报告DesiredSize为(0,0),因此ScrollViewer永远不会认为需要滚动。

请参见this StackOverflow answer,它建议使用网格而不是画布,并使用Margin属性进行定位。网格将根据其子项的大小和位置报告其大小,因此ScrollViewer将知道需要滚动。

更新:

ScrollViewer会给它的子项要求的大小,并且只有在子项大于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);

对于“画布”中的项目,您可以改为]

item.Margin = new Thickness(100, 200, 0, 0);

将其放置在一个单元格网格中的同一位置。


1
投票

Quartermeister's answer帮助我解决了这个问题。


0
投票

Akjoshi,

© www.soinside.com 2019 - 2024. All rights reserved.