ScrollViewer Problem

Hi. I have a sample code as follow:

private void WindowLoaded(Object sender, RoutedEventArgs e)
{
Canvas frameTop = new Canvas();
Canvas frameRight = new Canvas();
Canvas frameLeft = new Canvas();

DockPanel dockPanel = new DockPanel();

frameTop.VerticalAlignment = VerticalAlignment.Top;
frameTop.HorizontalAlignment = HorizontalAlignment.Left;

frameRight.VerticalAlignment = VerticalAlignment.Top;
frameRight.HorizontalAlignment = HorizontalAlignment.Right;

frameLeft.VerticalAlignment = VerticalAlignment.Top;
frameLeft.HorizontalAlignment = HorizontalAlignment.Left;

Button btn = null;
btn = new Button();
btn.Content = "Button Top ";
frameTop.Height = 100;
frameTop.Width = 600;
frameTop.Children.Add(btn);

btn = new Button();
btn.Content = "Button Left ";
btn.Width = 200;
frameLeft.Height = 500;
frameLeft.Width = 100;
frameLeft.Children.Add(btn);

btn = new Button();
btn.Content = "Button Right ";
frameRight.Height = 500;
frameRight.Width = 500;
frameRight.Children.Add(btn);

ScrollViewer scrollTop = new ScrollViewer();
ScrollViewer scrollRight = new ScrollViewer();
ScrollViewer scrollLeft = new ScrollViewer();

scrollTop.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollTop.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollTop.CanContentScroll = true;

scrollRight.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollRight.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollRight.CanContentScroll = true;

scrollLeft.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollLeft.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scrollLeft.CanContentScroll = true;

scrollTop.Content = frameTop;
scrollRight.Content = frameRight;
scrollLeft.Content = frameLeft;

DockPanel.SetDock(scrollRight, Dock.Right);
DockPanel.SetDock(scrollLeft, Dock.Left);
DockPanel.SetDock(scrollTop, Dock.Top);

dockPanel.Children.Add(scrollTop);
dockPanel.Children.Add(scrollLeft);
dockPanel.Children.Add(scrollRight);

this.Height = 600;
this.Width = 600;

this.AddChild(dockPanel);

}

The code is trying to create the relation for the objects:

ScrollViewer -> Canvas -> Button

The problem with the code is that, if the canvas size is smaller than button, the scrollviewer will not show the scrollbar, thus making only part of the button is viewable. In other words, I found that whether scrollviewer will show scrollbar is largely depends on the size of the directly content (in this case, canvas) regardless the actual content or children of canvas.

I would like to know how to make the scrollviewer awares of the actual content of canvas and show scrollbar accordingly even though canvas is smaller than its content. TQ in advance.

jordan



Answer this question

ScrollViewer Problem

  • dungcoi

    You're correct; the ScrollViewer is only aware of the size of it's child, no descendents. The way that you would make ScrollViewer "aware" of descendent sizes is to make sure the ScrollViewer's child is aware of it. This can be done by having a child panel which grows with the size of its children. Canvas does not do this purposefully but something like StackPanel, DockPanel, Grid or WrapPanel would.

  • Daeron

    I'm having the exact same problem.
    Has a solution been provided

    Thanks!


  • dzn

    If I don't resize the canvas prior to applying the transformation what I get is a canvas of the same size containing the scale content, that is the upper-left part that fits in the non-resized canvas.
    I've checked using the debugger and can assure you that the RenderTransform does not resize the canvas.
    However using LayoutTransform instead of RenderTransform works and in this case you don't need to resize the canvas.

  • Radu Motisan

    As a Canvas does not automatically resize - you must give it explicit Width/Height when you want to use it inside a ScrollViewer.
    In this sample the Canvas is larger than the ScrollViewer

    <ScrollViewer HorizontalScrollBarVisibility="Auto" Width="100" Height="100">
    <Canvas Width="400" Height="300">
    <Button Height="200" Width="180"/>
    </Canvas>
    </ScrollViewer>

    to enable the horizontal scroll bar you must explicitly set its Visibility (vertical scrollbar is a visible by default).

    If you want absolute positioning with automatic size calculation, you may choose a Grid and use Margins for the content elements.

    <ScrollViewer HorizontalScrollBarVisibility="Auto" Width="100" Height="100">
    <Grid>
    <Button Height="200" Width="180"/>
    <Button Margin="100,0,0,0" Height="200" Width="180"/>
    <Button Margin="0,100,0,0" Height="200" Width="180"/>
    </Grid>
    </ScrollViewer>



  • Wellnow

    I have solve the problem by copying the content of the Canvas in a StackPanel, as follows:
  • MikeBlig

    I am having this exact same problem. Could someone explain the best way to notify the scrollviewer of the scale change

    Thanks!

  • Boris Mueller

    Dave,

    What you're describing seems to be a 'workaround' rather than a solution. What you're doing is first tripling the size of your canvas, and then scaling it * 3 again. The effect this has is that your canvas will in the end be 9 times it's original size, even though it's content will look correctly zoomed because of your RenderTransform.

    The first multiplication notifies the ScrollViewer of the size change (by changing it!), and the second actually scales your content.

    You can get around this by setting your canvas LayoutTransform to the same transformation as your RenderTransform.

    One caveat, however - depending on how your UI is set up, that layout transform can be expensive!

    F.

    Dave Perry wrote:
    I have solve the problem by copying the content of the Canvas in a StackPanel, as follows:
  • Tomasz007

    I am having a simliar issue:

    Canvas inside a scrollviewer works great, until I apply a ScaleTransform to the Canvas. The scrollbars never recalculate, since I scale the canvas, rather than update the width/height.

    I too need a canvas for absolute positioning - I am working at the visual layer to display CAD vector geometry.

    Is this behavior by design

    F.


  • SunLiWei

    It is true that other Layout systems, like DockPanel, StackPanel etc will be aware of its children's sizing, and can grow as it is required by children, except for the Canvas. But the reason we are using Canvas is we require absolute positioning, and Canvas is the only way to do absolute positioning.

    Is there anyway to make Canvas be aware of its chilren content and make it resizeable so the ScrollViewer knows when to scroll the Canvas, maybe through some additional code implementing certain interfaces.

    So, the problem is Canvas has to be used for sure, due to absolute positioning, but how to make scrollviewer be aware of the children of Canvas.

    Thanks.


  • Olivier Moreau

    Hey!

    I am having the same problem, however, I Do use a StackPanel instead of a Canvas. But how can I make my StackPanels children aware of the scrollviewer


  • ScrollViewer Problem