Force a custom WPF Control to resize correctly

32,505

Solution 1

Your problem is that Canvas panels do not resize to fit their content.

You refered to Measure and Arrange. Are you familiar with WPF's two pass layout system? Read this article for more information: WPF's Layout System.

This article also describes what different panels do for layout. Each type of panel is different.

In WPF, elements are first given an opportunity to determine what size they will be. Panels can determine their size based on the size of their children, or they can ask for fixed size regardless of the size of their children. Canvas is an example of the latter.

Elements are next told what size they will be and asked to arrange themselves and their children.

The Grid panel type not only allows rows and columns, but is also very good at auto sizing to content.

The StackPanel type does not autosize at all in the dimension in which it is oriented, but it will autosize in the other dimension.

Canvas can auto size to fill a space, but it never allows it's children to auto size. It draws its children at the specified coordinates and does not care how big they are.

I would suggest trying a Grid with only one row/column.

Or you could create a new Canvas class that has better autosizing capabilities. During measure, you would want to measure the child elements and size your Canvas accordingly. You might find a class like this helpful down the road.

Here's an article on Auto Layout in WPF.

If you want to create a custom panel, here's a subtopic on it: Custom Panel Elements.

EDIT: One more thing: You can also bind the width/height of the child element to the ActualWidth and ActualHeight properties on the canvas so that the child will adjust the size of its parent. You can use a converter to set a size ratio if necessary.

Solution 2

did you try to wrap everything (your custom control contents) into a Viewbox? eg

 <UserControl>
    <Border BorderBrush="Black" BorderThickness="1">
        <Viewbox>
            <Grid>
                <TextBlock Name="txtDefault" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16" Foreground="Black" Opacity="0.5" Text="Default" />
                <TextBlock Name="txtValue" FontSize="16" Foreground="Black" Visibility="Collapsed" />
                <TextBlock Name="txtKey" Grid.Column="1" FontSize="18" Foreground="Black" Visibility="Collapsed" />
            </Grid>
        </Viewbox>
    </Border>
</UserControl>

Solution 3

You need to override MeasureOverride method of your control and return your desired size (the size of your canvas) from there. Then the parent control would resize itself to accommodate it's child (if it can).

Share:
32,505
Scott
Author by

Scott

By Day: Head Developer nah, sounds too naff Lead Developer hmmm still a bit naff Senior Developer makes me sound old.... Ninja... I can't even finish that one with a straight face its so 2008. I'm some guy that's been at Redgum since pretty much the get-go, we write software that others have deemed to be too difficult and generally fix projects that have gone off the rails. By Night: I spend time with my family and there's a pretty good chance my kid really is cuter than yours.

Updated on January 14, 2020

Comments

  • Scott
    Scott over 4 years

    I have written a WPF user control and part of it involves dynamically adding elements to a canvas which effects the height of said canvas. The canvas is nested within a grid. When I dynamically add my elements the height of the canvas changes, but the canvas ends up extending beyond the edge of the overall control rather than causing the control to resize and make itself taller. How can I force the control to resize correctly? I get the feeling I need to either call or override Measure or Arrange but I’m having no luck with either method – possibly because I’m calling them with incorrect parameters or possibly because they aren’t the correct methods to be calling.