Hide WPF Window Until Fully Loaded - c#

For my WPF application, I am storing several user settings like window position, window state, and whether or not to display a welcome dialog. The problem is that while everything is loading up, I see a lot of flashing and flickering as the windows are loaded in, and then more flickering when the window is maximized after reading in the settings.
I am already using the built-in WPF PNG splash screen functionality, but is there a way to completely hide the rendering of all windows until everything is fully loaded in?

Edit the Application.xaml, remove the StartUpUri, instead set the StartUp event handler.
In Application.xaml.cs, edit the startup event handler to display the splashscreen, load your resources, create everything, then create the main window and show it.
<Application
...
StartUp="OnStartUp"
/>
And:
private void OnStartUp(Object sender, StartupEventArgs e)
{
var settings = LoadSettingsFrom... // Call your implementation of load user settings
// Example only, in real app do this if's section on a different thread
if (settings.doShowSplashScreen)
{
var splashScreen = new SplashScreen();
splashScreen.Show();
}
// Load and create stuff (resources, databases, main classes, ...)
var mainWindow = new mainWindow();
mainWindow.ApplySettings(settings); // Call your implementation of apply settings
if (doShowSplashScreen)
{
// send close signal to splash screen's thread
}
mainWindow.Show(); // Show the main window
}

You can set the windows WindowState to Minimized, then handle the ContentRendered event and set the WindowState to Normal or Maximized.

There are functions , BeginInit and EndInit, if you change properties inside these functions like..
BeginInit();
...
... // Do your code Initialization here...
...
EndInit();
then your window will not render until the EndInit() is called, it will not flicker.

When does this loading occur? Code executed in the main Window's constructor should execute before the window is shown; if you load any required resources there, you should not see any flickering.

Related

Understand WPF Window Events

I see Windows have a Loaded event, but not a Loading event (as there is Closing and Closed events).
My expectation was that the Loaded event would occur before the window is actually displayed. However, looking at the Window Lifetime Events, it shows that the Loaded event occurs after Activated event.
I put some initialization code in the Loaded event and there is a delay after the window is displayed and before my content appears. So what is the best event handler to use for window initialization that should occur before the window is displayed?
You can override OnStartup() in App.xaml.cs, and do stuff before calling base.OnStartup(e);. I just checked and this is fired before the window's constructor.
Alternatively, set the window's visibility to Hidden in its xaml file, do your initialization in the constructor and then set the visibility to Visible once done. This won't remove the delay, but the delay is only caused by whatever your initialization code is doing, so it's unavoidable unless you go asynchronous.
Here's a simplified version of what I do (error handling removed). If the initialization takes a while, you may want to display a splash screen while you're doing your thing.
App.xaml:
<Application x:Class="MyProgram.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_StartUp" >
</Application>
App.xaml.cs:
namespace MyProgram
{
public partial class App : Application
{
private void App_StartUp(object sender, StartupEventArgs e)
{
// Create the model and MainWindow
MyModel model = CreateModel();
MainViewModel viewModel = new MainViewModel(model);
MainWindow = new MainWindow(viewModel); // Sets the DataContext
// Do things, like initialize your model
model.Initialize();
// Now show your window
MainWindow.Show();
}
}
}

CM bootstraper showing a window before the root view

I have a Caliburn.Micro bootstrapper where I use OnStartup() to check a view things and call DisplayRootViewFor<IShell> later. In some scenarios I must have the user to make an important decision or show some warning before the root view launches. I can do this by using WindowManager.ShowDialog().
But here is the problem: When I have no window shown before the root view, all works like expected.
When I show a window before the root view the DisplayRootViewFor() call is made but the application terminate immediately.
I guess this is because when I use the window manager to show a window before it gets the root view and closing it makes the WPF application thinking its main window is closed and it terminates automatically.
So how can I show a (modal) window before the root view?
I found one possible solution is:
Set Application.ShutdownMode to OnExplicitShutdown. Then I have to track when really shutting down the application like when the shell is closed I have to call System.Windows.Application.Current.Shutdown(); explicitly.
I am curious if there is also another way but I guess when the modal window is closed the for a moment the number of windows in the WPF application goes down to 0 the shutdown is triggered regardless if a new main window is established shortly after.
you can put your shutdown on your shell view on close as the shell view is the main window if the user close it means they want to close the exe.
private void ShellView_OnClosed(object sender, EventArgs e)
{
Application.Current.Shutdown();
}
Well, if someone else is having this problem, I solved it overriding the OnActivate method like this:
protected override void OnActivate()
{
_windowManager.ShowDialog(YOUR_WINDOW);
base.OnActivate();
}
Thus you don't have to set Application.ShutdownMode to OnExplicitShutdown and your application works normally.

Splash screen window does not load items

I'm trying to use a window as splash screen. I have this:
{
InitializeComponent();
new splash().ShowDialog();
}
in my main window to start up with and it works but on the window that I'm using as splash when I press start it stays blank. This is the code I'm using for the splash window:
public partial class splash : Window
{
public splash()
{
InitializeComponent();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
System.Threading.Thread.Sleep(3000);
Close();
}
As it is it just loads the window blank and after 3secs it moves on to the main window.
I want the splash window to load with a label and an image.
Any ideas?
Thanks
So, as I already mentioned it in my comment, here is an excellent guide on how to implement a splash screen for WPF applications. Also Microsoft offers an easier way if your splash screen is only an image (see here).
But the main problem with your code is the Sleep(3000) call, as it blocks the UI thread. Use a Timer instead, which you can start in the window loaded event handler, and close the window in the Timer's Elapsed event handler.
Hope this helps.
(Sorry for almost duplicating my comment, but at the third edit I realized it actually should be an answer :))

Setting Visibility="Hidden" on WPF Window never shows the window again

I have set the Visibility property of the main window to Hidden and added the following in Window_Loaded:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.Visibility = System.Windows.Visibility.Visible;
}
But it doesn't show up the Window. Any specific reason for this?
The window is not loaded until it is shown, as per your code it will not be shown until it is loaded. Obivously this cannot work like that, right?
I was having an issue with this as well and it seems changing the visibility alone on a main window doesn't work as H.B. pointed out. For my case, I wanted to not show the window until it was completely loaded and was able to achieve that by using the property I've linked to here, along with the Show() and Hide() functions on the Window object.
System.Windows.Window.ShowActivated
When initializing the window object don't set visibility to hidden, instead follow the next steps
Set the ShowActivated property to false this.ShowActivated = false;
Call the Hide() function on the window object this.Hide();
On your window loaded function from your original example call this.Show();
It is also possible in some WPF apps for the this reference not to work as expected, however if this is the case go to the XAML and find the name property of the window. You should be able to ref the window from the code via that name. Ex.
<Window x:Name="MainWindow">
//Code Behind Below
MainWindow.ShowActivated = false;

Splash Screen Example

I only want a simple Splash Screen Example.
Get the Code, Insert my picture, add 2 lines of code to load and finish.
But all I can google is so complex, that is too much. I only want a form with a picture that goes more and more transparent until it hides automaticly and my window is shown.
I tried the "prettygoodsplashscreen" from Codeproject, but don't work for me.
Lang is c#.net 2.0
Creating the splash screen can be as simple or complex as you make/want it to be.
private void Form1_Load(object sender, System.EventArgs e)
{
// Display the splash screen
var splashScreen = new SplashForm();
splashScreen.Show()
// On the splash screen now go and show loading messages
splashScreen.lblStatus.Text = "Loading Clients...";
splashScreen.lblStatus.Refresh();
// Do the specific loading here for the status set above
var clientList = _repository.LoadClients();
// Continue doing this above until you're done
// Close the splash screen
splashScreen.Close()
}
Obviously the Splash Screen itself is something that you'd have to decide how you want it to look...
In order for your splash screen to be areal splash screen, it shouldn't have other code than displaying about what it's doing (loading clients, for instance) or show the progress of application startup through a ProgressBar control.
Here are the steps:
Instantiate a BackgroundWorker for which you will launch the loading within the BackgroundWorker.DoWork() method;
Within your main Form_Load() event, call BackgroundWorker.RunWorkerAsync() method;
Still in your Form_Load() event, after your call to RunWorkerAsync(), instantiate and display your splash screen to your user SplashForm.ShowDialog()
Report progress from within your LoadClient() method, for instance, with the BackgroundWorker.ProgressChanged() event (you may also report what it is your BackgroundWorker is doing ("loading clients...");
In your RunWorkerCompleted() event, you may Splash.Close() your splash screen form.
I shall add some further details later on. Have to go now.

Categories