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.
No this is not possible (see snippet from MSDN below). However, if you want to have scrollbars and auto-resizing, consider using a Grid instead, 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.. :)
Grid lets you enjoy both worlds - As long as you're putting all elements into a single cell, you get both: Arbitrary positioning and auto-sizing. In general it is good to remember that most panel controls (DockPanel, StackPanel, etc) can be implemented via a Grid control.
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.
Hope this helps
I'm just copying illef's answer here but in answer to PilotBob, you just define a canvas object like this
public class CanvasAutoSize : Canvas { protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) { base.MeasureOverride(constraint); double width = base .InternalChildren .OfType<UIElement>() .Max(i => i.DesiredSize.Width + (double)i.GetValue(Canvas.LeftProperty)); double height = base .InternalChildren .OfType<UIElement>() .Max(i => i.DesiredSize.Height + (double)i.GetValue(Canvas.TopProperty)); return new Size(width, height); } }
and then use CanvasAutoSize in your XAML.
<local:CanvasAutoSize VerticalAlignment="Top" HorizontalAlignment="Left"></local:CanvasAutoSize>
I prefer this solution to the one presented above that uses the grid as it works through attached properties and just requires setting less properties on the elements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With