views:

5819

answers:

4

I would like my canvas to automatically resize to the size of its items, so that the ScrollViewer scroll bars have the correct range. Can this be done in XAML?

<ScrollViewer HorizontalScrollBarVisibility="Auto" x:Name="_scrollViewer">
    <Grid x:Name ="_canvasGrid" Background="Yellow">
        <Canvas x:Name="_canvas" HorizontalAlignment="Left" VerticalAlignment="Top" Background="Green"></Canvas>
        <Line IsHitTestVisible="False" .../>
    </Grid>
</ScrollViewer>

In the above code the canvas always has size 0, though it doesn't clip its children.

+7  A: 

No this is not possible...

From MSDN:

Canvas is the only panel element that has no inherent layout characteristics. A Canvas has default Height and Width properties of zero, unless it is the child of an element that automatically sizes its child elements. Child elements of a Canvas are never resized, they are just positioned at their designated coordinates. This provides flexibility for situations in which inherent sizing constraints or alignment are not needed or wanted. For cases in which you want child content to be automatically resized and aligned, it is usually best to use a Grid element.

If you want to have scrollbars, consider using a Grid, and use the Margin property to position your items on this Grid.. Grid will tell the ScrollViewer how big he wants to be, and you will get the scrollbars.. Canvas will always tells the ScrollViewer he doesn't need any size.. :)

Hope this helps

Arcturus
I switched from Canvas to Grid and it worked, after some tweaking. I had to make two changes: (1) everywhere that I used to set the attached properties Canvas.Left and Canvas.Top, I now set the regular properties Margin.Left and Margin.Top (Margin.Right and Margin.Bottom can be left at 0); (2) use HorizontalAlignment="Left" and VerticalAlignment="Top" on each element in the Grid. The default "Stretch" mode can cause elements to end up in the center when the Margins are 0.
Qwertie
+1  A: 

I see you've got a workable solution, but I thought I'd share.

<Canvas x:Name="topCanvas">
    <Grid x:Name="topGrid" Width="{Binding ElementName=topCanvas, Path=ActualWidth}" Height="{Binding ElementName=topCanvas, Path=ActualHeight}">
     ...Content...
    </Grid>
</Canvas>

The above technique will allow you to nest a grid inside a canvas and have dynamic resizing. Further use of dimension binding makes it possible to mix dynamic material with static material, perform layering, etc. There are too many possibilities to mention, some harder than others. For example I use the approach to simulate animatating content moving from one grid location to another - doing the actual placement at the animation's completion event. Good luck.

Redsplinter
A: 
<viewbox><canvas> <uielements /> </canvas></viewbox>
Joe
+1  A: 

I think you can resize Canvas by overriding MeasureOverride or ArrangeOverride methods.

This job is not difficult.

You can see this post. http://illef.tistory.com/entry/Canvas-supports-ScrollViewer

I hope this helps you.

Thank you.

illef