Как рассчитать размер окна, не относящегося к клиенту, в WPF? - PullRequest
33 голосов
/ 17 мая 2011

WPF имеет класс SystemParameters , который предоставляет множество системных показателей. На моем компьютере я заметил, что нормальное окно имеет заголовок высотой 30 пикселей и границу шириной 8 пикселей. Это на Windows 7 с включенной темой Aero:

Non-client area - Aero

Однако SystemParameters возвращает следующие значения:

SystemParameters.BorderWidth = 5
SystemParameters.CaptionHeight = 21

Здесь я отключил тему Aero:

Non-client area - classic

Теперь SystemParameters возвращает следующие значения:

SystemParameters.BorderWidth = 1
SystemParameters.CaptionHeight = 18

Как вычислить фактические наблюдаемые значения, используя SystemParameters?

Ответы [ 4 ]

32 голосов
/ 17 мая 2011

Для окна с изменяемым размером вам нужно использовать другой набор параметров для вычисления размера:

var titleHeight = SystemParameters.WindowCaptionHeight
  + SystemParameters.ResizeFrameHorizontalBorderHeight;
var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;

Эти размеры будут меняться при изменении темы.

9 голосов
/ 17 мая 2011

Я почти уверен, что функция GetSystemMetrics (которую класс SystemParameters вызывает внутри с соответствующими аргументами) - это , возвращающая правильные значения для вашей системы, этопросто возвращая правильные значения в случае, если тема Aero отключена.Включив Aero, вы получите более широкие границы и более высокие заголовки окон - все это сочные графические качества.

Если вы хотите получить правильный размер этих элементов окна, независимо от текущей темы пользователя (помните,Вы можете запустить Windows Vista и более поздние версии с классической темой, темой Aero Basic или полной темой Aero, каждая из которых будет иметь элементы пользовательского интерфейса разного размера), вам нужно использовать другой метод, доступный в Vista и более поздних версиях.

Вам необходимо отправить в окно WM_GETTITLEBARINFOEX сообщение , чтобы запросить расширенную информацию в строке заголовка.wParam не используется и должен быть равен нулю.lParam содержит указатель на TITLEBARINFOEX структуру , которая получит всю информацию.Вызывающая сторона отвечает за выделение памяти для этой структуры и установку ее члена cbSize.

Чтобы сделать все это из приложения .NET, вам, очевидно, потребуется выполнить P / Invoke.Начните с определения необходимых вам констант, а также структуры TITLEBARINFOEX:

internal const int WM_GETTITLEBARINFOEX = 0x033F;
internal const int CCHILDREN_TITLEBAR = 5;

[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFOEX
{
    public int cbSize;
    public Rectangle rcTitleBar;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
    public int[] rgstate;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
    public Rectangle[] rgrect;
}

Затем определите функцию SendMessage соответствующим образом:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
                                          IntPtr hWnd,
                                          int uMsg,
                                          IntPtr wParam,
                                          ref TITLEBARINFOEX lParam);

И, наконец, вы можете вызватьвесь этот беспорядок, используя что-то вроде следующего кода:

internal static TITLEBARINFOEX GetTitleBarInfoEx(IntPtr hWnd)
{
    // Create and initialize the structure
    TITLEBARINFOEX tbi = new TITLEBARINFOEX();
    tbi.cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX));

    // Send the WM_GETTITLEBARINFOEX message
    SendMessage(hWnd, WM_GETTITLEBARINFOEX, IntPtr.Zero, ref tbi);

    // Return the filled-in structure
    return tbi;
}

РЕДАКТИРОВАТЬ: Теперь протестировано и работает на моем ноутбуке под управлением Windows 7.

0 голосов
/ 28 июля 2017

Для большого окна

NON_CLIENT_AREA_HEIGHT = SystemParameters.WindowNonClientFrameThickness.Top +
                SystemParameters.WindowNonClientFrameThickness.Bottom +
                SystemParameters.WindowResizeBorderThickness.Top +
                SystemParameters.WindowResizeBorderThickness.Bottom;

            NON_CLIENT_AREA_WIDTH = SystemParameters.WindowNonClientFrameThickness.Left +
                SystemParameters.WindowNonClientFrameThickness.Right +
                SystemParameters.WindowResizeBorderThickness.Left +
                SystemParameters.WindowResizeBorderThickness.Right;
0 голосов
/ 17 мая 2011

См. Следующее:

http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2009/09/20/wpf-quick-tip-how-to-get-wpf-window-client-area-size.aspx

Я предполагаю, что вы пытаетесь вычислить размер, который вы должны сделать в Окне приложений, чтобы дать правильное количество клиентской области для полного отображения некоторого содержимого WPF?

Если это так, то просто помните, что пиксели WPF имеют разрешение 96 точек на дюйм, и ваш дисплей может работать с другим разрешением на дюйм ... также, как уже упоминалось в других ответах, тема влияет на размер вашего основного окна, чтобы получите желаемую клиентскую зону.

В качестве альтернативы вы можете использовать MinWidth / MinHeight для дочернего элемента управления Window.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...