Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: How to make canvas auto-resize?

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.

like image 771
Qwertie Avatar asked May 12 '09 23:05

Qwertie


2 Answers

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

like image 161
Arcturus Avatar answered Sep 25 '22 13:09

Arcturus


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.

like image 30
MikeKulls Avatar answered Sep 24 '22 13:09

MikeKulls