#.net #wpf #focus #splash-screen
#.net #wpf #фокус #заставка
Вопрос:
Когда экранный экран закрывается (вручную или с помощью автоматического закрытия), он крадет фокус основного окна во время анимации затухания. Это приводит к тому, что заголовок главного окна переключается с активного на неактивный (серый) на активный. Есть ли какой-нибудь трюк, чтобы не дать заставке украсть фокус?
Ответ №1:
Сообщите заставке, что MainWindow является ее родительским окном. Когда дочернее окно теряет фокус, его родительское получает фокус. Если родительского элемента нет, решение принимает оконный менеджер.
Заставка.Показать (основное окно);
Редактировать:
Я только что узнал, что есть класс SplashScreen . Похоже, вы используете этот класс, а не просто обычную форму, как я предполагал.
Итак, я только что создал простое приложение WPF с заставкой, и для меня упомянутого эффекта не произошло. Главное окно не потеряло фокус.
Я бы посоветовал вам комментировать элементы кода инициализации вашего приложения до тех пор, пока мигание не прекратится. Тогда у вас есть отправная точка для дополнительных исследований, почему фокус теряется.
ПРАВКА2:
Не зная вашего кода, я попытался воспроизвести это явление, и это было не слишком сложно. Что бы я ни пробовал, изменение фокуса всегда происходило, когда главное окно уже было показано и имело фокус.
Поэтому лучшее решение, которое я вижу, — вручную отобразить главное окно после вызова метода Close () заставки:
-
Удалите StartupUri из App.xaml
-
Показать заставку после запуска приложения и инициализации ресурсов. После (в настоящее время исправленной) задержки закройте заставку и покажите главное окно:
public partial class App : Application
{
const int FADEOUT_DELAY = 2000;
SplashScreen splash = new SplashScreen("splash.jpg");
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
splash.Show(false, true);
var worker = new BackgroundWorker();
worker.DoWork = (sender, ea) =>
{
Thread.Sleep(1000);
splash.Close(new TimeSpan(0, 0, 0, 0, FADEOUT_DELAY));
// you could reduce the delay and show the main window with a nice transition
Thread.Sleep(FADEOUT_DELAY);
Dispatcher.BeginInvoke(new Action(() => MainWindow.Show()));
};
worker.RunWorkerAsync();
MainWindow = new MainWindow();
// do more initialization
}
}
Комментарии:
1. Метод Show SplashScreen не принимает окно в качестве параметра. Я использую встроенный объект SplashScreen из WPF, это не обычное окно.
2. Вы указали задержку затухания при закрытии? Когда задержка очень короткая, это может быть незаметно?
3. @Joshua: Нет. Вы пытались удалить задержку затухания? Решает ли это вашу проблему с фокусом?
4. Да, когда вы указываете нулевую задержку, главное окно не теряет фокус. Но мой вопрос в том, как сохранить фокус во время анимации затухания, а не как ее отключить 😉
5. Спасибо за все ваше время и исследования. Я уже использовал событие OnStartup для отображения заставки. И . У Show есть «самый верхний» флаг, который точно предназначен для удержания заставки сверху, в то время как вы уже показываете свое MainWindow. Мой загрузочный код состоит из двух этапов, и для улучшения «воспринимаемой производительности» для пользователя я уже показываю mainwindow, продолжая «второй этап» процесса загрузки. Если мне нужно дождаться FADEOUT_DELAY, мое приложение, похоже, загружается медленнее для конечного пользователя.
Ответ №2:
Используя ILSpy, я обнаружил, что SplashScreen.Close
метод вызывается SetActiveWindow
в какой-то момент, в результате чего окно экрана slpash становится активным в момент, когда оно начинает закрываться. (По крайней мере, в .NET 4.0.) Я добавил вызов в my MainWindow.Focus
сразу после вызова SplashScreen.Close
, и это решает проблему.
В противном случае я мог видеть, как главное окно было неактивным только во время анимации затухания. Кроме того, я показываю модальное диалоговое окно при загрузке главного окна, и оно остается активным. Но когда это диалоговое окно закрывается, главное окно больше не будет фокусироваться, и вместо этого я окажусь в окне Visual Studio или в любом другом, запустившем мое приложение. Вставка Focus
вызова сверху также помогает в этой ситуации.
Кстати, вот хорошая статья, в которой объясняется, как использовать SplashScreen
класс вручную вместо параметра project file: http://tech.pro/tutorial/822/wpf-tutorial-using-splash-screens-in-sp1
Это некоторый код из моего приложения:
В App.xaml.cs:
/// <summary>
/// Application Entry Point.
/// </summary>
[STAThread]
public static void Main()
{
splashScreen = new SplashScreen("Splashscreen.png");
splashScreen.Show(false, true);
Thread.Sleep(2000); // For demonstration purposes only!
App app = new App();
app.InitializeComponent();
app.Run();
}
В моем главном окне команда инициализации ViewModel (главное окно уже полностью видно):
private void OnInitCommand()
{
ConnectDatabase();
App.SplashScreen.Close(TimeSpan.FromMilliseconds(500));
MainWindow.Instance.Focus(); // This corrects the window focus
SomeDialog dlg = new SomeDialog();
dlg.Owner = MainWindow.Instance;
if (dlg.ShowDialog() == true)
{
// Do something with it
}
// Now the main window is focused again
}