Страницы

Поиск по вопросам

суббота, 7 декабря 2019 г.

Как показать невидимое окно?

#c_sharp #wpf #winforms


У меня есть окно, которое выполняет какой-то процесс с визуализацией. И мне надо
чтобы при запуске приложение оно работало, но не показывалось (то есть чтобы произошло
событие Load). При этом у пользователя всегда есть возможность его показывать и скрывать.
Проблема в том что у меня не получается решить этот вопрос без начального мерцания
из-за подобного кода.

SomeWindow.Show();
SomeWindow.Hide();


Ни в Windows Forms, ни в WPF не вижу решения этой проблемы.

Проблема также в том, что окно показывается в TaskBar, но только когда оно видимое.
Поэтому мне не подходят хаки вроде


Установки прозрачности окна.
Установки нулевой широты, высоты и удаления рамок.
Вынос окна за пределы экрана и т.д.


Для чего это надо и почему нельзя всё вынести в какой-нибудь Task? Потому что код
выполняемый окном зависит от визуализации. Мне нужно чтобы человек мог скрывать и показывать
окно когда и сколько угодно, но чтобы его состояние было таким же как будто его не
скрывали.
    


Ответы

Ответ 1



Просто так вам не получится вызвать событие Loaded: оно вызывается лишь тогда, когда ваше окно реально было показано. Но, возможно, у вас сработает обходной путь, который сработал в моём проекте. Для начала, мы отделим контент окна в UserControl. Окно пусть будет пустым. Контрол назовём SimpleUserControl для примера. Теперь мы в начале работы приложения создаём контрол, но не показываем его, таким образом: public partial class App : Application { protected override async void OnStartup(StartupEventArgs e) { base.OnStartup(e); var uc = new SimpleUserControl(); // создали контрол // возможно, надо установить DataContext var size = new Size(100, 100); // фейковый размер uc.Measure(size); // заставляем пробежать layout engine uc.Arrange(new Rect(size)); uc.UpdateLayout(); // дождёмся выполнения пустой лямбды на фоновом приоритете, // это даст время привязкам разрешиться await Dispatcher.CurrentDispatcher.InvokeAsync( () => { }, DispatcherPriority.Background); // теперь можно работать с контролом. я просто сделаю паузу для примера await Task.Delay(9000); // и вставить его в окно: new MainWindow() { Content = uc }.Show(); } } При этом Loaded на контроле всё ещё не вызывается (оно вызовется только при показе), но у вас подконтролы будут находиться в «рабочем» состоянии.

Ответ 2



Получил ответ на англ. SO. Этот же код работает для WPF если заменить FormWindowState на WindowState. Суть в том, что надо сначала чтобы перед "показом" установить (в коде или дизайнере): SomeWindow.ShowInTaskbar = false; SomeWindow.WindowState = FormWindowState.Minimized; Затем выполнить код SomeWindow.Show(); SomeWindow.Hide(); И сразу после этого подготавливаем окно для нормального отображения при последующих вызовах SomeWindow.Show: SomeWindow.ShowInTaskbar = true; // Если надо чтобы форма показывалась на панели быстого запуска. SomeWindow.WindowState = FormWindowState.Normal; // или FormWindowState.Maximized если надо Это можно превратить в метод расширения для Windows Forms: public static class FormHelper { public static void ShowInvisible(this Form form) { // сохраняем параметры окна bool needToShowInTaskbar = form.ShowInTaskbar; FormWindowState initialWindowState = form.WindowState; // делаем окно невидимым form.ShowInTaskbar = false; form.WindowState = FormWindowState.Minimized; // показываем и скрываем окно form.Show(); form.Hide(); // восстанавливаем параметры окна form.ShowInTaskbar = needToShowInTaskbar; form.WindowState = initialWindowState; } } или для WPF: public static class WindowHelper { public static void ShowInvisible(this Window window) { // сохраняем параметры окна bool needToShowInTaskbar = window.ShowInTaskbar; WindowState initialWindowState = window.WindowState; // делаем окно невидимым window.ShowInTaskbar = false; window.WindowState = WindowState.Minimized; // показываем и скрываем окно window.Show(); window.Hide(); // восстанавливаем параметры окна window.ShowInTaskbar = needToShowInTaskbar; window.WindowState = initialWindowState; } }

Ответ 3



Как я понял, при создании формы: её не должно быть видно, должно сработать событие Load, её иконка должна появиться на таскбаре, форма не не должна мелькнуть. По-моему, установка прозрачности в ноль перед показом, а после показа в единицу полностью решает проблему. var form = new Form(); form.Opacity = 0; form.Load += Form_Load; form.Show(); form.WindowState = FormWindowState.Minimized; form.Opacity = 1; Событие вызывается, форма не мелькает, на таскбаре отображается.

Комментариев нет:

Отправить комментарий