更改画布内控件的位置后,滚动条不可见

发布于 2024-09-05 21:24:07 字数 1022 浏览 6 评论 0原文

我创建了一个继承自 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 后 ,但没有任何反应;我是否遗漏了什么或由于某些错误而发生这种情况?

更新

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

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

I created a custom canvas control inheriting from WPF Canvas. I am using it like this in main window -

<ScrollViewer
    HorizontalScrollBarVisibility="Auto"
    VerticalScrollBarVisibility="Auto">
    <RTD:RTDesignerCanvas
        Margin="5"
        Background="White"
        x:Name="canvas1"
        Focusable="True"
        AllowDrop="True">
    </RTD:RTDesignerCanvas>
</ScrollViewer>

Everything works fine but when I try to set the position of controls inside it like this

Canvas.SetTop(item, 200);

scrollbars are not visible and control is hidden down somewhere. Interestingly, if I add another control to it scroll bars are visible and I can scroll downwards to see the previous control.

I tried to use

base.InvalidateVisual();
base.UpdateLayout();
base.InvalidateArrange();

after changing items Top or Left but nothing happens; Am I missing something or this happens due to some bug?

Update:

to clarify, say I have a canvas having its width, height as 100, 100. Now if I move a control(already added in canvas) using Canvas.SetLeft(myControl, 200) then it will move to a position which is not visible by default and scroll bars are also disabled, so there is no way to see that control.

Now if I add another control to Canvas, ScrollBars appear correctly and I can see the previous control by scrolling.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

错爱 2024-09-12 21:24:07

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

请参阅此 StackOverflow 答案,其中建议使用网格画布并使用 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);

画布中处理某个项目,则可以将

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

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

Did you override MeasureOverride in your custom Canvas? Canvas will always report a DesiredSize of (0, 0), so the ScrollViewer will never think it needs to scroll.

See this StackOverflow answer which suggests using a Grid instead of a Canvas and using the Margin property for positioning. The Grid will report its size based on the size and position of its children, so the ScrollViewer will know it needs to scroll.

Update:

ScrollViewer will give its child ask much size as it asks for, and will only need to scroll if the child is larger than the ScrollViewer. In order to have it scroll properly, you'll need to report a DesiredSize that is large enough to include all of your child controls. You can do that by overriding MeasureOverride like this:

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;
}

An easier solution, however, is to take advantage of the fact that the Grid class will already measure like this. You can use the Margin property of the child elements to position them exactly instead of the Canvas.Left and Canvas.Top properties. If you are currently doing

Canvas.SetLeft(item, 100);
Canvas.SetTop(item, 200);

for an item in the Canvas, you could instead do

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

to position it in the same place within a one-cell Grid.

↙温凉少女 2024-09-12 21:24:07

Quartermeister的回答帮助我解决了这个问题。

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

Quartermeister's answer helped me in solving this issue.

I had to use base.InvalidateMeasure() explicitly after each operation to refresh the canvas and make the scrollbars visible.

硬不硬你别怂 2024-09-12 21:24:07

Akjoshi,

这一定是一个错误。下次画布隐藏在某个地方时,对其运行 Snoop 并检查它在哪里。确保检查以下画布属性:ActualWidthActualHeightOpacityVisibility

Akjoshi,

It has to be a bug. Next time the canvas becomes somewhere hidden, run Snoop on it, and check where it is. Makes sure to check the following canvas properties: ActualWidth, ActualHeight, Opacity, Visibility

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文