Здравствуйте
Мне надо сохранять позицию/размер формы при выходе и восстанавливать их при запуске. Использую JSON, так как он простой и удобный.
Проблема в том, что сохранять надо только в том случае, когда форма не свёрнута и не развёрнута. А это значит, что если закрыть форму когда она развёрнута, то предыдущие значения не сохранятся и будут утеряны. Следовательно, надо ловить события Maximized и Minimized, в которых запоминать позицию/размер формы и сохранять их если форма была закрыта когда она свёрнута или развёрнута… подумал я и обнаружил, что этих событий тупо нет Приплыли! Видимо, за 20 лет эти события никому, кроме меня одного, не понадобились А иначе, почему ещё их не подвезли?
В интернете нашел примерно такой костыль:
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
IntPtr SC_MAXIMIZE = new IntPtr(0xF030);
IntPtr SC_MINIMIZE = new IntPtr(0xF020);
IntPtr SC_RESTORE = new IntPtr(0xF120);
switch (message.Msg)
{
case WM_SYSCOMMAND:
if (message.WParam == SC_MAXIMIZE)
{
System.Diagnostics.Debug.WriteLine($"maximized: {Location} {Size}");
}
else if (message.WParam == SC_MINIMIZE)
{
System.Diagnostics.Debug.WriteLine($"minimized: {Location} {Size}");
}
else if (message.WParam == SC_RESTORE)
{
System.Diagnostics.Debug.WriteLine("restored");
}
break;
}
base.WndProc(ref message);
}
Казалось бы, работает, но нет, нифига! Привет Бригману.
Сообщения SC_MAXIMIZE и SC_RESTORE приходят только если нажать мышкой на кнопку “развернуть”. Если делать даблклик по неклиентской области или нажимать win+вверх/win+вниз, то ничего не приходит. Возможно, приходит что-то другое, но я не проверял и не знаю, как это проверить.
Если правильно помню, на Delphi тоже такая фигня была, но там она как-то решалась (не помню как).
А тут что делать?
Это получается, что надо сначала проверить, есть ли в конфиге значение x. Если его нет, то ставим WindowsDefaultLocation и пропускаем загрузку y. А если есть, то делаем то же самое для y. А если в конфиге есть x, но нет y, то варианта два. Либо делать Top = 0, либо ставить WindowsDefaultLocation и выбрасывать значение x. Чё-то слишком замудрёный алгоритм получается, чтобы всего-то координаты окна загрузить
Как узнать, где должно было появиться окно, как если бы стояло StartPosition == WindowsDefaultLocation? Чтобы не ставить нули, если в конфиге отсутствуют нужные параметры (x или y, или оба). На WinAPI, например, была константа CW_USEDEFAULTS и не приходилось заниматься мазохизмом.
О, какой прикол нашёл
Если обратиться к хэндлу окна, то работает и всё замечательно.
Ещё одно подтверждение тому, что WinForms был написан по накурке, чтобы прям как у Borland, только своё.
А куда оно денется? Разве что пользователь зачем-то решить файл сломать ) Для таких редких случаев можно проверять, что оба есть.
Устанавливать только одно из них, а второе оставлять по умолчанию, вряд ли хорошая идея. Например, может быть два монитора разных размеров, и может получиться, что х был от первого монитора, а y от другого, и окно будет за их пределами.
Еще в идеале надо как минимум проверять, что они не выходят за пределы экрана. Мониторы и их настройки могут меняться.
Так это просто приводит к созданию окна. Можно вместо этого просто подождать какое-нибудь событие )
Вот видите. Мы опять напоролись на полное отсутствие логики. Конструктор создаёт экземпляр класса, но не создаёт окно формы, ради которого этот класс и был создан Событие Load приходит только при первом появлении окна на экране (которое совсем не обязательно должно быть показано сразу). Так а почему нет события в момент именно создания окна, когда всё нужное уже создано, но ещё не показано? В чём логика делать это (создавать окно) при обращении к хэндлу?
Ну мало ли. Если будет какая-нибудь ошибка, то можно будет легко отредактировать конфиг, удалив параметр и он примет дефолтное значение.
Если бы я не хотел, чтобы юзер лез в конфиг, то взял бы какой-нибудь бинарный сериализатор.
Я бы так не сказал. И не важно, что за пределы экрана может выйти.
Ну так оно и при наличии обоих (x,y) может за пределы экрана выйти, если юзер поменяет конфигурацию мониторов и не сбросит конфиг. Я раньше гуглил, и похоже, что за этим очень трудно уследить (по-этому, я даже не пытаюсь это делать). А если один из параметров отсутствует, то окно, наоборот, почти всегда появится на экране, какой бы ни была их конфигурация. Вернее, не почти всегда, а шансов на это будет больше.
Каким образом выход за пределы экрана лучше стандартной позиции?)
Отсутствие одного из параметров это ж дико редкая ситуация, зачем что-то придумывать для такого случая, особенно если оно может вызвать новые проблемы.
Идеально может и сложно, но какие-то базовые проверки вполне можно добавить.
Ну и например это решение выглядит вполне норм: https://stackoverflow.com/a/987090/964478
Да, согласен. Такая проверка нужна. Не знал, что есть свойство AllScreens. Но если юзер додумается поставить мониторы диагонально друг другу, тогда не будет работать. Окно может остаться в невидимой область.
Кстати, раньше я просто делал иконку в трее и пункт меню, который возвращал окно в центр экрана.
Но VCL такой VCL и винда такая винда, что иконка в трее не всегда появляется.