Reputation: 65
Using Windows 11 and WPF, when I change the background color of the window, the window flashes white, then after a couple frames the proper color of the program shows. This is really annoying, since the program I am working on is small and has dark mode. Checking the internet, there aren't many results, but the "solutions" typically involve initially minimizing the window, then showing it when everything is loaded. This is fine, except on Windows 11 it creates a really distracting "show" animation, and it's somewhat more of a flash then a solution. Some have recommended a splash screen, but this shouldn't be necessary since the program I'm working on is very simple.
There is a chance that this is either:
Steps to reproduce:
dotnet new wpf
add a background attribute to the window (I have tried setting the background to the Window in C# instead of XAML and setting it to the layout, neither make a difference), and set it to a color
dotnet build
and run the program.
Upvotes: 1
Views: 504
Reputation: 62110
Edit
Read this for the historical background behind the problem.
For the actual solution, skip mine and read Anson Kindred's instead.
This was discussed with Microsoft here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/bdb414fe-9abb-408c-8935-486e1795755b/wpf-window-with-black-background-flashes-white-when-first-shown?forum=wpf
The answer from Microsoft's side was that "it is a known issue" and that "they will take this into serious account" and provides "for reference" a link to some question-and-answer here on Stack Overflow which is about some largely unrelated problem which has received completely unrelated answers.
In any case, that was in 2010, so don't hold your breath for any solution from Microsoft.
I have the same problem, using WPF with .NET 7.0, target OS version "7.0", running under Windows 10. I also see this problem with many popular applications, for example:
In order to solve this problem I had to do the following:
Set up a splash-screen. (Yes, I know, the author of the question does not want a splash-screen, but many people will see this question who would not mind having one.) The splash-screen can be a fully transparent PNG file, which is virtually indistinguishable from no splash-screen.
Set dpiAware
to true
in app.manifest. (Microsoft recommends some additional magical incantation in the App.config file, but that was not necessary.)
Remove any actual functionality from the main window, so that its loading does not get slowed down by anything. This means:
MainWindow
into a new class called MainView
MainWindow
contain a MainView
which is initially null;MainWindowViewModel
into a new class MainViewModel
MainWindowViewModel
instantiate the MainViewModel
on the first idle event. (At that point also create the MainView
inside the MainWindow
in order to present the MainViewModel
.)Note that doing only 1 or 2 out of the 3 steps described above does not work for me; all 3 steps are necessary. (I know, this is preposterous, but that's what it is. Welcome to Windows, where preposterousness is the order of the day.)
Also note:
Invoking user32.dll
:SetProcessDPIAware()
from the constructor of the application had no effect.
Fiddling with the "Target OS Version" and "Supported OS Version" in Project Properties had no effect.
Upvotes: 1
Reputation: 75
For anyone coming here in the year of our lord 2023...The best solution I have found for this is to go with the minimization based solution and disable the minimize/maximize animation. This seems to be the best of all worlds, with no unwanted animations, no flash, and fairly minimal code changes.
First make sure to remove the StartupUri from your App.xaml so that the window is not loaded automatically. Then in your App.xaml.cs you can add something like:
protected override void OnStartup(StartupEventArgs e)
{
Window mainWindow = new MainWindow();
MainWindow.WindowState = WindowState.Minimized;
mainWindow.Loaded += MainWindow_Loaded;
mainWindow.Show();
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
((Window)sender).WindowState = WindowState.Normal;
}
Which will start the window minimized and maximize it when it's done loading.
Then you just need to chant the magic incantation to disable the maximize animation:
const int DWMWA_TRANSITIONS_FORCEDISABLED = 3;
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref bool attrValue, int attrSize);
public static void DisableTransitions(Window window)
{
bool value = true;
DwmSetWindowAttribute(new WindowInteropHelper(window).Handle, DWMWA_TRANSITIONS_FORCEDISABLED, ref value, Marshal.SizeOf(value));
}
Which I call from my MainWindow's OnSourceInitialized
method.
You can even turn the transition animations back on after the MainWindow is loaded and it works no problem.
Upvotes: 2