Изменение размера формы из сообщения WM_SIZE - PullRequest
1 голос
/ 18 февраля 2012

У меня есть форма с минимальной установленной высотой, потому что я не хочу, чтобы она изменяла размеры выше определенной точки, когда она находится в режиме «минималистического отображения».

Когда пользователь пытается максимизировать окно, привязывая его к верхней части экрана, окно максимизируется, но высота окна составляет всего 240 пикселей (установленный максимальный размер). Если я попытаюсь обработать сообщение WM_SIZE, когда wParam равно SIZE_MAXIMIZED, любая попытка установить высоту формы будет проигнорирована.

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

Конечно, ни одно из этих сообщений не публикуется, если окно развернуто с помощью ShowWindow(SW_MAXIMIZE) или когда aero-snapped в верхней части экрана.

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

Текущий код:

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x0112) { // WM_SYSCOMMAND
        if (m.WParam == new IntPtr(0xF030)) { // Maximize event - SC_MAXIMIZE from Winuser.h
            // The window is being maximized
            this.MaximumSize = new Size(9999, 9999);
            ToggleDeviceDisplay(true);
            linkToggleDeviceList.Visible = false;
        }
    } else if (m.Msg == 0x00A3) { // WM_NCLBUTTONDBLCLK - Double clicking on window title bar, min or max
        if (this.WindowState == FormWindowState.Normal) {
            if (grpDeviceList.Visible == false) {
                this.MaximumSize = new Size(9999, 9999);
                ToggleDeviceDisplay(true);
            }
            this.WindowState = FormWindowState.Maximized;
            linkToggleDeviceList.Visible = false;
        } else {
            this.WindowState = FormWindowState.Normal;
            linkToggleDeviceList.Visible = true;
        }
        return;
    } else if (m.Msg == 0x0005) { // WM_SIZE
        if (m.WParam == new IntPtr(0x02)) { // SIZE_MAXIMIZED
            // CANT GET WINDOW TO GO TO FULL-SCREEN FROM HERE
            this.MaximumSize = new Size(9999, 9999);

             // THE LINE BELOW DOESN'T WORK, probably because it is already being sized
            this.Height = Screen.FromHandle(this.Handle).WorkingArea.Size.Height;
        } else if (m.WParam == new IntPtr(0x00)) { // SIZE_RESTORED
            linkToggleDeviceList.Visible = true;
        }
    }
    base.WndProc(ref m);
}

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

Я знаю, что я мог бы запустить таймер или что-то еще из сообщения, чтобы оно изменило размер так быстро, что пользователь не сразу заметил бы, что он не был полноэкранным, но это просто ужасный взлом.

EDIT:

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

Спасибо.

Ответы [ 3 ]

2 голосов
/ 18 февраля 2012

Мне кажется, что вы пытаетесь сделать простую вещь слишком сложным способом. Я обработал бы сообщение WM_GETMINMAXINFO , которое отправляется в ваше окно всякий раз, когда его размер или позиция собирается измениться. Обработка этого сообщения дает вам возможность указать максимальное или минимальное значение для каждого из этих атрибутов, эффективно предотвращая его уменьшение или уменьшение по вашему желанию.

Я не буду публиковать много примеров кода, потому что ваш вопрос показывает, что вы уже знаете, как переопределить WndProc и обрабатывать оконные сообщения. Единственное, что вам нужно сделать, это определить структуру MINMAXINFO в управляемом коде. Примерно так:

[StructLayout(LayoutKind.Sequential)]
struct POINT
{
    public int X;
    public int Y;
}

[StructLayout(LayoutKind.Sequential)]
struct MINMAXINFO
{
    public POINT ptReserved;
    public POINT ptMaxSize;
    public POINT ptMaxPosition;
    public POINT ptMinTrackSize;
    public POINT ptMaxTrackSize;
}

Используйте Marshal.PtrToStructure для преобразования указателя, содержащегося в свойстве Message.LParam, в экземпляр структуры MINMAXINFO, определенной выше. Итак, внутри вашего WndProc метода вы бы сделали что-то вроде:

MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(msg.LParam, typeof(MINMAXINFO));

Обновление:

На скриншотах, которые вы опубликовали, похоже, что два разных дисплея идентичны, единственное отличие состоит в том, отображается ли DataGridView внизу. GroupBox вверху отображается независимо от размера формы.

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

Внутри этого метода обработчика событий проверьте текущие размеры вашей формы. Если оно достаточно большое, установите для свойства Visible элемента управления DataGridView значение true. Если его недостаточно, переключитесь на «минимальный режим», установив DataGridView.Visible = false.

Это не очень технически сложное решение, но, похоже, оно должно достичь всех ваших желаемых целей. Мотивация, насколько я понимаю, заключается в том, чтобы предоставить более простой интерфейс, когда форма слишком мала, чтобы можно было все видеть, и расширить этот интерфейс, когда форма больше. Если вы обработаете событие Resize и проверите фактический размер формы после того, как это событие сработало, вы не ошибетесь.

Альтернативное решение - просто включить свойство AutoScroll и всегда показывать оба элемента управления. Все, что нужно сделать пользователю, это прокрутить вверх или вниз, чтобы увидеть все, что он хочет. WinForms позаботится обо всем остальном.

2 голосов
/ 18 февраля 2012

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

1 голос
/ 18 февраля 2012

Таким образом, вы хотите, чтобы ваша форма имела минимальный размер, максимальный размер и при этом могла максимизировать ее, используя двойной щелчок в строке заголовка, кнопку максимизации и Aero snap?Tricky :-) Вот решение.

Установите MinimumSize в свойствах и затем напишите 2 события:

private void Form1_Resize(object sender, EventArgs e)
{
    if (WindowState == FormWindowState.Normal)
    {
        MaximumSize = new Size(maxWidth, maxHeight);
    }
}

и:

private void Form1_ResizeEnd(object sender, EventArgs e)
{
    MaximumSize = new Size(0, 0);
}

Это будет делатьтрюк.По крайней мере, работает на моей машине: -)

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