Заставка.Close() крадет фокус основного окна

#.net #wpf #focus #splash-screen

#.net #wpf #фокус #заставка

Вопрос:

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

Ответ №1:

Сообщите заставке, что MainWindow является ее родительским окном. Когда дочернее окно теряет фокус, его родительское получает фокус. Если родительского элемента нет, решение принимает оконный менеджер.

Заставка.Показать (основное окно);

Редактировать:

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

Итак, я только что создал простое приложение WPF с заставкой, и для меня упомянутого эффекта не произошло. Главное окно не потеряло фокус.

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

ПРАВКА2:

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

Поэтому лучшее решение, которое я вижу, — вручную отобразить главное окно после вызова метода Close () заставки:

  1. Удалите StartupUri из App.xaml

  2. Показать заставку после запуска приложения и инициализации ресурсов. После (в настоящее время исправленной) задержки закройте заставку и покажите главное окно:


 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
}