Подтвердить что ты не робот

Как вычислить размер окна без клиента в WPF?

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?

4b9b3361

Ответ 1

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

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

Эти размеры изменяются при изменении темы.

Ответ 2

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

Если вы хотите получить правильный размер этих элементов окна, независимо от текущей темы пользователя (помните, что вы можете запускать Windows Vista и дальше с помощью темы Classic, темы 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;
}

EDIT: Теперь протестировано и работает на моем ноутбуке под управлением Windows 7.

Ответ 3

Обратитесь к следующему:

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 точек на дюйм, а ваш дисплей может работать на разных dpi... также, как упоминалось в других ответах, тема влияет на то, насколько большой размер вашего основного окна должен быть получите желаемую клиентскую область.

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

Ответ 4

Для повторно отображаемого окна

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;