tags:

views:

1153

answers:

3

I want to set my WPF window's initial client size. I'm not seeing a straightforward way to do this.

Specifically, when my window opens, I want it to be sized just big enough for its contents to fit without needing scrollbars. But after it's shown, I want the window to be freely resizable (either larger or smaller).

If I set Width and Height attributes on my Window element, that sets the non-client (outer) size, which isn't useful. Once the titlebar and resize borders eat into that space, the client area will no longer be big enough for its content, and I'll have scrollbars. I could compensate by picking a larger size, but both titlebar height and border thickness are user-customizable (as well as the defaults varying by OS version) and won't necessarily be the same on a different machine.

I can set Width and Height on the window's content element (a <Grid> in this case), and then set the Window's SizeToContent attribute to WidthAndHeight. That gets the window's initial size exactly where I want it. But then things don't resize anymore -- I can resize the window, but its content doesn't resize with it, because I specified a fixed size.

Is there any way to set a Window's initial client size, preferably without code-behind? (I'll take code-behind if that's the only way, but I'd prefer a XAML-only approach if anyone has one.)

+4  A: 
Oren Trutner
A: 

I do the following in the constructor and add ResizeMode="CanResizeWithGrip" in the xaml, but it kind of depends on how much space your content occupies on startup

public Window1()
{
    this.Height = SystemParameters.WorkArea.Height;
    this.Width = SystemParameters.WorkArea.Width;
}
Klerk
+4  A: 

You can do it in code-behind on the Load event handler in one of two ways:

NOTE: The content of the LayoutRoot Grid is the same in both examples, but the Width and Height on the LayoutRoot are only specified in example A.

A) ClearValue on the the Window's SizeToContent and on the content's Width and Height:

using System.Windows;

namespace WpfWindowBorderTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ClearValue(SizeToContentProperty);
            LayoutRoot.ClearValue(WidthProperty);
            LayoutRoot.ClearValue(HeightProperty);
        }
    }
}

assuming a page layout like (note the SizeToContent setting and Loaded event handler on the Window and the Width and Height specified on the LayoutRoot):

<Window x:Class="WpfWindowBorderTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" SizeToContent="WidthAndHeight" Loaded="Window_Loaded">
    <Grid x:Name="LayoutRoot" Width="300" Height="300" Background="Green">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" />
        <Rectangle Grid.Row="0" Grid.Column="0" Width="75" Height="75" Fill="Red" />
        <Rectangle Grid.Row="1" Grid.Column="1" Fill="Yellow" />
        <Rectangle Grid.Row="1" Grid.Column="1" Width="225" Height="225" Fill="Red" />
    </Grid>
</Window>

or

B) setting the Window's Width and Height accounting for the System-specific client window frame sizes:

using System.Windows;

namespace WpfWindowBorderTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            const int snugContentWidth = 300;
            const int snugContentHeight = 300;

            var horizontalBorderHeight = SystemParameters.ResizeFrameHorizontalBorderHeight;
            var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;
            var captionHeight = SystemParameters.CaptionHeight;

            Width = snugContentWidth + 2 * verticalBorderWidth;
            Height = snugContentHeight + captionHeight + 2 * horizontalBorderHeight;
        }
    }
}

assuming a proportional page layout like (note no SizeToContent setting or Loaded event handler on the Window or Width and Height specified on the LayoutRoot):

<Window x:Class="WpfWindowBorderTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1">
    <Grid x:Name="LayoutRoot" Background="Green">
        <Grid.RowDefinitions>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" />
        <Rectangle Grid.Row="0" Grid.Column="0" Width="75" Height="75" Fill="Red" />
        <Rectangle Grid.Row="1" Grid.Column="1" Fill="Yellow" />
        <Rectangle Grid.Row="1" Grid.Column="1" Width="225" Height="225" Fill="Red" />
    </Grid>
</Window>

I haven't been able to come up with a way to do it declaratively in XAML as yet.

Tim Erickson
I finally got back to a project where I needed this, and your first solution does exactly what I want. Thanks!
Joe White