Bringing the main window forward after turning off the splash screen

I am having a problem with a custom implementation of the wpf splash screen. The problem is that after loading and displaying MainWindow it is sometimes not brought to the fore. Call () cannot be activated. It can be 1/10 times. The application runs on Windows7 / 64.

Here is an example (full source sample )

public partial class App : Application { private Splash _splash; private SplashVM _viewModel; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // starts splash in separate GUI thread StartSplash(); // continues on loading main application in main gui thread LoadMainAppFakeSteps(1000, 3); // tells splash screen to start shutting down Stop(); // Creates mainwindow for application // The problem is that the mainwindow sometimes fails to activate, // even when user has not touched mouse or keyboard (ie has not given any other programs or components focus) MainWindow = new Shell(); MainWindow.Show(); MainWindow.Activate(); } private void StartSplash() { _viewModel = new SplashVM(); var thread = new Thread(SplashThread); thread.SetApartmentState(ApartmentState.STA); thread.IsBackground = true; thread.Start(_viewModel); } private void SplashThread(object vm) { _splash = new Splash(); _splash.DataContext = vm; _splash.Show(); System.Windows.Threading.Dispatcher.Run(); _splash = null; _viewModel = null; } private void LoadMainAppFakeSteps(int stepDelayMs, int numSteps) { for (int i = 1; i <= numSteps; i++) { _viewModel.Text = i.ToString(); Thread.Sleep(stepDelayMs); } } private void Stop() { if (_splash == null) throw new InvalidOperationException("Not showing splash screen"); _splash.Dispatcher.BeginInvokeShutdown(DispatcherPriority.Normal); } } 

I tried this:

 MainWindow = new Shell(); MainWindow.Topmost = true; MainWindow.Show(); MainWindow.Activate(); MainWindow.Topmost = false; 

and it seems to work, thanks to all your suggestions

+7
source share
3 answers
 MainWindow = new Shell(); MainWindow.Topmost = true; MainWindow.Show(); MainWindow.Activate(); MainWindow.Topmost = false; 
+3
source

Windows has built-in protection that prevents focus theft from the currently active user stream. This means that you can successfully use the Activate() form from another window that currently has focus.

For example, if a dialog box is displayed in the main window of the application, the windows will gladly make him concentrate, because the main application is simply concentrated in the same stream and can transmit this.

In the case of a splash screen, your main shape may not be a focused window for several reasons. Either because your splash screen has focus, or because the end user started downloading your application, and then started doing something else (maybe playing with his email or browser), which means that your application does not have focus generally. (Can you see the window on the taskbar trying to get focus?)

In the first case, you want your splash screen to activate the main form and then close it. (As before, to close the screen saver, and then try to activate the main form). If you mess with threads, you can also opt out of using wincon pinvoke to call SetForegroundWindow() with a window handle. You can pass a window handle around the threads. This ensures that windows respond to your focus request, since the focused form is currently making a request.

Here's a neat article on the subject of focus theft:

The only way that Windows 2000 and Windows XP allows the Application Window to go to the front is if the thread it runs on is the thread of the foreground window at that time. So, you have to attach the thread of your application to the foreground thread and then bring the application window to the foreground. After that you need to disconnect your stream (all this happens only if the user has another application window as an active foreground window). Source: Forcing Forward

Someone redid this article code in C # in this other StackOverflow post: https://stackoverflow.com/a/168389/ (It seems that some definitions for PInvoke calls are missing, but you can easily find on Google using "pinvoke" and the name of the Win32 interface you need.)

+4
source

In addition to hkon's answer, you should check if your splash screen is the current front window before stealing focus using TopMost = true.

  [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); public static bool IsForeground(this Window window) { var windowHandle = new WindowInteropHelper(window).Handle; var foregroundWindow = GetForegroundWindow(); return windowHandle == foregroundWindow; } 
+1
source

All Articles