Set the MinWidth and MinHeight based on SizeToContent Property

We are developing a WPF application for a client where they want to be able to use the SizeToContent=”WidthAndHeight” attribute on the window. This attribute is great because it allows WPF to size the window to the size of the controls on the window. This is especially important as they need the labels to grow and shrink when they localize the labels for English, Spanish and German. Once the initial size is set by WPF, they want that initial size to be the minimum height and minimum width for that window. As it turns out, this is very easy to accomplish in WPF.

The Form
Figure 1 shows a sample form that uses a <Grid> control and row and columns for the labels, text boxes and buttons. Using a grid control allows your controls to grow and shrink as you re-size the window.

Set Initial Width/Height
Figure 1: Setting the initial MinWidth and MinHeight properties

Take a look at the XAML for this window.

<Window x:Class="SetInitialMinWidthHeight.winMain"
        x:Name="winTest"
        xmlns="http://schemas.microsoft.com/winfx/2006
                     /xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Set Initial MinWidth/MinHeight"
        WindowStartupLocation="CenterScreen"
        MinWidth="{Binding ElementName=winTest,
                           Path=InitialMinWidth}"
        MinHeight="{Binding ElementName=winTest,
                            Path=InitialMinHeight}"
        SizeToContent="WidthAndHeight"
        Loaded="Window_Loaded">
  <Window.Resources>
     <!-- SOME RESOURCES HERE -->
  </Window.Resources>
  <Grid Margin="10">
    <Grid.RowDefinitions>
      <!-- ROW DEFINITIONS HERE -->
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <!-- COLUMN DEFINITIONS HERE -->
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Row="0"
               Grid.Column="0"
               Text="First Name" />
    <TextBox Grid.Row="0"
             Grid.Column="1"
             x:Name="txtFirstName" />
    <TextBlock Grid.Row="1"
               Grid.Column="0"
               Text="Last Name" />
    <TextBox Grid.Row="1"
             Grid.Column="1"
             x:Name="txtLastName" />
    <Button Grid.Row="2"
            Grid.Column="1"
            Content="Submit" />
  </Grid>
</Window>

Most of this window is pretty normal grid layout XAML code, but take a look at the MinWidth, MinHeight and SizeToContent properties. Notice that the SizeToContent property is set to WidthAndHeight. This allows the window to size itself based on how much room the child controls take up. Take a look at the binding used for the MinWidth and MinHeight properties. Each of these two properties are binding to Dependency properties that have been created on the window itself. Notice that the binding refers to the “winTest”, which has been set as the x:Name of the Window.

The Dependency Properties

In order to data-bind from XAML to a property on your form you need to create a Dependency Property. Both the “InitialMinHeight” and “InitialMinWidth” properties that are being bound are dependency properties. You create dependency properties using the DependencyProperty.Register() static method. To create our InitialMinHeight property you first create a static DependencyProperty with the name InitialMinHeightProperty. Notice the “Property” suffix added at the end.

C#
protected static DependencyProperty InitialMinHeightProperty =
  DependencyProperty.Register(
    "InitialMinHeight", typeof(double), typeof(winMain));

protected static DependencyProperty InitialMinWidthProperty =
  DependencyProperty.Register(
    "InitialMinWidth", typeof(double), typeof(winMain));

VB
  Protected Shared InitialMinHeightProperty As DependencyProperty _
    = DependencyProperty.Register("InitialMinHeight", _
                          GetType(Double), GetType(winMain))

  Protected Shared InitialMinWidthProperty As DependencyProperty _
    = DependencyProperty.Register("InitialMinWidth", _
                          GetType(Double), GetType(winMain))

Once you have created these dependency properties, you now create normal properties. However, in the getter and setters you call the GetValue and SetValue methods that are part of the WPF Window class.

C#
protected double InitialMinHeight
{
  get { return (Double)GetValue(InitialMinHeightProperty); }
  set { SetValue(InitialMinHeightProperty, value); }
}

protected double InitialMinWidth
{
  get { return (Double)GetValue(InitialMinWidthProperty); }
  set { SetValue(InitialMinWidthProperty, value); }
}

VB
Protected Property InitialMinHeight() As Double
  Get
    Return DirectCast(GetValue(InitialMinHeightProperty), _
                       Double)
  End Get
  Set(ByVal value As Double)
    SetValue(InitialMinHeightProperty, value)
  End Set
End Property

Protected Property InitialMinWidth() As Double
  Get
    Return DirectCast(GetValue(InitialMinWidthProperty), _
                       Double)
  End Get
  Set(ByVal value As Double)
    SetValue(InitialMinWidthProperty, value)
  End Set
End Property

Now that you have created these properties, you can now set them during the Loaded event procedure.

C#
private void Window_Loaded(object sender, RoutedEventArgs e)
{
  // Set dependency properties after form's height/width
  // has been set initially
  InitialMinWidth = this.ActualWidth;
  InitialMinHeight = this.ActualHeight;
}

VB
Private Sub Window_Loaded(ByVal sender As Object, _
  ByVal e As RoutedEventArgs)
  ' Set dependency properties after form's width/height
  ' has been set initially
  InitialMinWidth = Me.ActualWidth
  InitialMinHeight = Me.ActualHeight
End Sub

The ActualWidth and ActualHeight properties are set with whatever the values are that have been determined by WPF. You retrieve these values and put them into the dependency properties. The dependency properties allow the values to be updated and put into the MinWidth and MinHeight property of the Window.

Summary

In this article you learned how to set an initial minimum width and height. Using dependency properties and data binding you can have a WPF window set its initial size using SizeToContent, save those settings, then set the MinWidth and MinHeight on the Window.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Set Initial Min Width and Height" from the drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

 

2 Comments

  • You don't need dependency property for this, plain CLR properties and INotifyPropertyChanged can do exactly the same with lesser effort.

  • Andrew,

    Well... I actually had trouble doing the binding to the Window properties when using INotifyPropertyChanged. Not sure why. Try changing it to INotify... and see if you experience this too. Would love to know if you find something different.

Comments have been disabled for this content.