如何获取WPF窗口的客户区大小?

19

在WinForms中,Form有一个ClientSize属性(从Control继承),它返回其客户区域的大小,即标题栏和窗口边框内部的区域。

我在WPF中没有看到类似的东西:没有ClientSize、ClientWidth、ClientHeight、GetClientSize()或其他任何我可以想到猜测名称的东西。

我该如何获取WPF窗口的客户区域大小?

5个回答

12

你可以通过获取最顶层的子元素,将this.Content转换为其类型,并调用.RenderSize方法来获得其大小。

<Window x:Class="XML_Reader.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="400" Width="600" WindowStyle="SingleBorderWindow">
    <Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    </Grid>
</Window>

((Grid)this.Content).RenderSize.Height
((Grid)this.Content).RenderSize.Width

编辑:

如Trent所说,ActualWidthActualHeight也是可行的解决方案。基本上是获取我上面提到内容的更简单方法。


我还要考虑到内容的边距。 - username

9
var h = ((Panel)Application.Current.MainWindow.Content).ActualHeight;
var w = ((Panel)Application.Current.MainWindow.Content).ActualWidth;

1
@WelshKing - Loaded事件已触发了吗?在窗口渲染之前是不会有大小的。 - Tristan
我不明白为什么人们一直发布这个建议。ActualWidth和ActualHeight与我的Width和Height变量完全相同,但是当我使用win32 API进行检查时,我知道客户端矩形区域显然更小。 - Meme Machine

2

以下是一种实现方式。XAML 代码如下:

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <Canvas>
    </Canvas>
</Window>

C#:

using System.Windows;

using System.IO;
using System.Xml;
using System.Windows.Controls;

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

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            double dWidth = -1;
            double dHeight = -1;
            FrameworkElement pnlClient = this.Content as FrameworkElement;
            if (pnlClient != null)
            {
                dWidth = pnlClient.ActualWidth;
                dHeight = pnlClient.ActualHeight;
            }
        }
    }
}

1
我使用了一个Grid且设置了VerticalAlignment=Top。结果是,该Grid不再填充父级窗口(这是它的默认行为,但VerticalAligment属性破坏了它)。
我通过在Grid周围放置一个空的Border解决了这个问题。该Border填充整个窗口内容,它具有与WPF窗口默认边框相同的尺寸。
为了让Grid填充主窗口,我使用了绑定:
<Border BorderThickness="0" x:Name=Main> <Grid VerticalAlignment="Top" Height="{Binding ElementName=Main, Path=ActualHeight}"> ... </Grid> </Border>

0

所有建议的解决方案都基于使用 Windows.Content 的大小来知道窗口内实际可用的大小,就像这样:

var h = ((Panel)Application.Current.MainWindow.Content).ActualHeight;

当然,这仅在Window.Content不为null时才有效。如果您想从代码中设置Window.Content,那么问题就来了,您需要知道有多少可用空间。

另一个问题是,上面的代码仅在第一次布局循环完成后提供可用空间(即在Window_Loaded事件中)。但是,如果您需要在第一次布局循环期间知道可用空间怎么办?例如,因为您在Windows.OnRender()期间绘制到窗口中?

任何Window的可视树中的第一个控件始终是一个Border,即使Window.Content为null。有趣的是,即使RenderSize.ActualSize可能仍为零,Border.RenderSize已经有一个值。我猜原因是Border的大小不取决于Window.Content,而只取决于窗口的大小(除非当然使用Window.SizeToContent)。

我建议将代码放置在 Window.SizeChanged 事件中。因为每次窗口大小改变时,您的内容也需要相应更改。您不能使用事件参数提供的大小,这会给您整个窗口的大小,但您可以像这样获取窗口内可用大小:

var h = ((Border)GetVisualChild(0)).RenderSize.Height;

如果你重写 Windows.OnRender(),你也可以使用那行代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接