1ctinus
1ctinus

Reputation: 65

How would I create a WPF window with a custom background color without a white flash?

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:

  1. a Driver/Graphics problem
  2. a bug with WPF itself

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

Answers (2)

Mike Nakis
Mike Nakis

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:

  • Any chromium-based web-browser
  • TortoiseGit when configured to use the system colors, and the system colors are dark.

In order to solve this problem I had to do the following:

  1. 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.

  2. Set dpiAware to true in app.manifest. (Microsoft recommends some additional magical incantation in the App.config file, but that was not necessary.)

  3. Remove any actual functionality from the main window, so that its loading does not get slowed down by anything. This means:

    • Move all of the contents of MainWindow into a new class called MainView
    • Have MainWindow contain a MainView which is initially null;
    • Move all of the functionality of MainWindowViewModel into a new class MainViewModel
    • Have 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

Anson Kindred
Anson Kindred

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

Related Questions