如何设置WPF窗口的启动ClientSize?

时间:2009-07-04 05:29:02

标签: wpf size

我想设置WPF窗口的初始客户端大小。我没有看到这样做的简单方法。

具体来说,当我的窗口打开时,我希望它的大小足够大,以使其内容适合而不需要滚动条。但是在显示之后,我希望窗口可以自由调整大小(更大或更小)。

如果我在Window元素上设置Width和Height属性,则会设置非客户端(外部)大小,这是无用的。一旦标题栏和调整大小边框进入该空间,客户区将不再足够大,其内容,我将有滚动条。我可以通过选择更大的尺寸进行补偿,但标题栏高度和边框厚度都是用户可自定义的(以及OS版本的默认值),并且在不同的机器上不一定相同。

我可以在窗口的内容元素上设置Width和Height(在本例中为<Grid>),然后将Window的SizeToContent属性设置为WidthAndHeight。这使窗口的初始大小正好在我想要的位置。但事情不会再调整大小了 - 我可以调整窗口的大小,但是它的内容不会随之调整大小,因为我指定了一个固定的大小。

有没有办法设置Window的初始客户端大小,最好没有代码隐藏? (如果这是唯一的方法,我将采取代码隐藏,但如果有人有,我会更喜欢仅使用XAML的方法。)

6 个答案:

答案 0 :(得分:20)

您可以通过以下两种方式之一在Load事件处理程序的代码隐藏中执行此操作:

注意:LayoutRoot网格的内容在两个示例中都相同,但LayoutRoot上的宽度和高度仅在示例A中指定。

A)Window的SizeToContent上的ClearValue以及内容的宽度和高度:

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);
        }
    }
}

假设页面布局类似(注意Window上的SizeToContent设置和Loaded事件处理程序以及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>

B)为系统特定的客户端窗口框架大小设置Window的宽度和高度:

使用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;
        }
    }
}

假设比例页面布局类似(注意窗口上没有SizeToContent设置或Loaded事件处理程序,或者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>

我还没有想出办法在XAML中以声明方式进行此操作。

答案 1 :(得分:12)

您可以删除XAML中的窗口宽度和高度属性,并添加SizeToContent =“WidthAndHeight”。这会将窗口的初始尺寸设置为其内容,但仍允许您调整其大小。

<Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" SizeToContent="WidthAndHeight">
    <Grid>
        <TextBlock Text="How to set WPF window’s startup ClientSize?"/>
    </Grid>
</Window>

启动时,它看起来像这样:

alt text http://img7.imageshack.us/img7/1285/onstart.png

然而你仍然可以用鼠标拉伸它:

alt text http://img16.imageshack.us/img16/6687/stretched.png

答案 2 :(得分:6)

我花了很长时间才能想出整个故事。很难在网上找到这个问题的纯XAML(零代码背后)答案,所以这里是我的。

当我们在Visual Studio WPF设计器中设计一个Window时,标准(默认情况下)方式是在Width上定义HeightWindow属性,就像在XAML中一样:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="75" Width="190">
    <Grid>
        <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" />
        <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/>
    </Grid>
</Window>

设计师预览如下所示:

enter image description here

一切看起来都很酷,但是当我们运行应用程序时,根据当前的Windows版本,主题和所有显示设置jazz,运行时窗口的概率有99%可能与设计相似一。以下是我在Windows 8.1上看到的内容:

enter image description here

最初的解决方案就像Oren使用SizeTocontent属性的答案一样。它基本上告诉WPF从它的内容(又名&#34;客户端大小&#34;)中定义窗口大小,而不是窗口本身(又名&#34;客户端大小+所有非客户端/ chrome) / border完全无法控制的东西&#34;)。

因此,我们可以将内容定义为固定大小,如下所示:

<Window x:Class="WpfApplication1.MainWindowSizeToContentCentered"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" SizeToContent="WidthAndHeight">
    <Grid Height="40" Width="180">
        <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" />
        <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/>
    </Grid>
</Window>

现在,运行时窗口看起来正是我们想要的(请注意,网格的高度和宽度与原始窗口的高度和宽度完全相同 - 40/180 vs 75/190 - ,这很好,就像在设计模式中一样,你现在可以忘记窗口高度和宽度属性永远):

enter image description here

调整窗口大小时的行为如何?像这样,网格是居中的,如果你想要这种行为,这很好:

enter image description here

但是,如果我们想要问题中的行为,(&#34;我可以调整窗口大小,但其内容不会随之调整大小,因为我指定了固定大小。&#34;),这也是原始行为,而不是指定宽度和高度,我们可以使用MinWidthMinHeight,如下所示:

<Window x:Class="WpfApplication1.MainWindowSizeToContentResizable"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" SizeToContent="WidthAndHeight">
    <Grid MinHeight="40" MinWidth="180">
        <Button Content="Right" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75" />
        <Button Content="Left" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="75"/>
    </Grid>
</Window>

运行时窗口看起来相同,但调整大小体验现在与原始默认窗口布局相当:

enter image description here

这应该是默认的WPF设计器布局恕我直言。

答案 3 :(得分:2)

我在构造函数中执行以下操作,并在xaml中添加ResizeMode =“CanResizeWithGrip”,但这取决于您的内容在启动时占用的空间

public Window1()
{
    this.Height = SystemParameters.WorkArea.Height;
    this.Width = SystemParameters.WorkArea.Width;
}

答案 4 :(得分:0)

这是一个完全本机的方法,不需要任何XAML,并且可以在显示Window之前起作用。

public unsafe override void SetSize(int width, int height, WindowSizeType type)
        {
            if (type == WindowSizeType.WorkingArea)// aka client area
            {
                // get native HWND handle
                IntPtr handle = new WindowInteropHelper(window).EnsureHandle();

                // get window rect and size
                RECT rect = new RECT();
                int result = GetWindowRect(handle, ref rect);
                if (result == 0) throw new Exception("GetWindowRect failed");
                int rectWidth = rect.right - rect.left;
                int rectHeight = rect.bottom - rect.top;

                // get client rect and size
                RECT clientRect = new RECT();
                result = GetClientRect(handle, ref clientRect);
                if (result == 0) throw new Exception("GetClientRect failed");
                int clientRectWidth = clientRect.right - clientRect.left;
                int clientRectHeight = clientRect.bottom - clientRect.top;

                // increase size based on client side decoration delta
                width = width + (rectWidth - clientRectWidth);
                height = height + (rectHeight - clientRectHeight);

                // apply new adjusted window size
                result = SetWindowPos(handle, IntPtr.Zero, 0, 0, width, height, SWP_NOMOVE);
                if (result == 0) throw new Exception("SetWindowPos failed");
            }
            else
            {
                window.Width = width;
                window.Height = height;
            }
        }

        #region SetSize native Helpers
        [StructLayout(LayoutKind.Sequential)]
        struct RECT
        {
            public int left, top, right, bottom;
        }

        private const string lib = "User32.dll";

        [DllImport(lib, EntryPoint = "GetWindowRect")]
        private extern static int GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [DllImport(lib, EntryPoint = "GetClientRect")]
        private extern static int GetClientRect(IntPtr hWnd, ref RECT lpRect);

        [DllImport(lib, EntryPoint = "SetWindowPos")]
        private extern static int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
        private const int SWP_NOMOVE = 0x0002;
        #endregion

答案 5 :(得分:0)

我不知道,为什么您为此需要复杂的代码。这对我总是很好:

<Window x:Class="Loadsheet_2._0.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:Loadsheet_2._0"
    mc:Ignorable="d"
    Title="MainWindow" MinHeight="635" MinWidth="1200" SizeToContent="WidthAndHeight" ResizeMode="CanResize">