【问题标题】:ScrollBars are not visible after changing positions of controls inside a Canvas更改 Canvas 内控件的位置后,滚动条不可见
【发布时间】:2010-06-17 11:56:52
【问题描述】:

我创建了一个继承自 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


    【解决方案1】:

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

    请参阅this StackOverflow answer,它建议使用 Grid 而不是 Canvas 并使用 Margin 属性进行定位。 Grid 将根据其子项的大小和位置报告其大小,因此 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);
    

    对于 Canvas 中的项目,您可以改为这样做

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

    将其放置在单格网格内的相同位置。

    【讨论】:

    • 感谢 Quartermeister 的回复,我没有在自定义画布中覆盖 MeasureUverride;从您的回答中我不清楚我是否应该覆盖它?但是,是的,您是对的,“ScrollViewer 永远不会认为它需要滚动”,这正是正在发生的事情。使用 Grid 不是一个选项,因为我具有移动、调整大小等功能,而 Canvas 是必须的。
    • 我的错,我不知道我是怎么错过的。我实际上正在覆盖它并在其中执行相同的操作。今天我发现某些操作根本没有调用此方法(这就是滚动条不可见的原因)。我必须在每次操作后显式使用 InvalidateMeasure() 来刷新画布。
    【解决方案2】:

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

    我必须在每次操作后显式使用 base.InvalidateMeasure() 来刷新画布并使滚动条可见。

    【讨论】:

      【解决方案3】:

      阿克乔希,

      它必须是一个错误。下次画布隐藏在某个地方时,在其上运行Snoop,并检查它的位置。确保检查以下画布属性:ActualWidthActualHeightOpacityVisibility

      【讨论】:

      • 感谢 Anvaka,实际上我的画布并没有隐藏,而是其中的控件。我已更新问题以使其更清楚。
      猜你喜欢
      • 1970-01-01
      • 2010-11-17
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-25
      • 2012-01-21
      • 1970-01-01
      相关资源
      最近更新 更多