Improve WPF Application Perceived Cold Startup Performance Using Splash Screen - c#

My WPF Application startup is slow (Cold startup), and I want to make the application main window appear as soon as the user double-click on the application’s icon.
I read this Blog and I want to add a Splash screen to avoid this delay. I added a splash screen to my application (PNG Image) But I have a questions :
How can I add the initialize code to improve startup, Or the splash screen will shown until the application loaded all the required components ?

It depends on where you load the resources that are so time consuming that the MainWindow gets delayed so much. If you are already creating those in the <App.Resouces /> block in XAML then it's tricky.
When they are created as resources for your view model in the <MainWindow.Resources /> then quite simply create a tool window or similar containing your splash screen and show it within the Application_Startup event like:
public partial class App : Application
{
// A Splash-Window to overlay until everything is ready.
public SplashWindow AppLauncher = new SplashWindow();
private void Application_Startup(object sender, StartupEventArgs e)
{
AppLauncher.lblText.Content = "Loading data...";
AppLauncher.Show();
}
}
And when all resources are loaded in the MainWindow then on the Loaded event hide/dispose the window again.
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
(App.Current as App).AppLauncher.Close();
}
}

Related

Duplicate icons in system tray when the single instance app is reopened again without fully closed

Recently I found an issue in my single instance c# wpf desktop application.
Initially, I opened my application and the icon was shown in the system tray. If I close the app using the close icon on windows, it will be run in the background and it can be opened from where it is left off using the system tray icon.
If I tried to open the app again like a regular way instead of using the system tray, there exists a duplicate icon in the system tray. However, hovering on the duplicate icons makes them disappear.
Is there any way to halt this issue of creating duplicates?
As Raymond Chen stated, you are not properly deleting your notification icon in your code. When your app closes, you need to hide and dispose the NotifyIcon properly that you are using.
If you don't properly hide and dispose the icon, then the icon will remain in the system tray even though the process has terminated. If you hover the mouse over the icon, it will then disappear. To prevent this "phantom" tray icon, you need to clean it up.
For example:
MainWindow.xaml.cs:
using System.Windows.Forms;
public partial class MainWindow : Window
{
private NotifyIcon taskbarIcon;
public MainWindow()
{
InitializeComponent();
this.Closing += MainWindow_Closing;
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (taskbarIcon != null)
{
taskbarIcon.Visible = false;
taskbarIcon.Dispose();
taskbarIcon = null;
}
}
}

how to close a WPF Dialog Window when user try to touch past window screen

Please look at image,
It has two windows, red one opens after green one.
How could I close red windows when user touch green screen?
Also I have using
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
Close();
}
But this works only when user open another application
here is my green window code, that opens red window
MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Window1 w=new Window1();
w.ShowDialog();
}
I cannot give you a direct answer since I do not do WPF programming, but an approach I use on IOS is to have one big form, the outer part is transparent and
it actually contains one huge button, which is also transparent, only the Window1 is visible. On the button press event close window1.
But I am pretty sure you should have a way to detect click events on the green part and then close the window1. Maybe add some event listener to some component you place on the green part.
See this answer:
how to close a WPF Dialog Window when the user clicks outside it
Here is a answer I copied:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
Close();
}
}

Reset Controls for WPF

I began using C# and WPF a few months ago and now I thought I'd try to learn some new techniques like using threading. So I have an app that I want to run all the time (using an infinity while loop) but show the dialog (main window) every minute. So I am doing this by using Threading and here is how i am doing this:
public MainWindow()
{
InitializeComponent();
while (true)
{
callmyfunction()
system.Threading.Thread.Sleep(1000);
}
}
In my callmyfunction(), I am calling the dialog (which is the main WPF application) so it will show. Here's how i am doing it:
public void callmyfunction()
{
this.ShowDialog();
}
I have a regular button and when you click on it, it should hide the main window. So my button function is like this:
private void Button_Click2(object sender, RoutedEventArgs e)
{
this.Hide();
}
So what I am doing is, I am loading the main window normally and it has a button, when I click on that button, it should hide the main window and the window should sleep as per the milli-seconds I specified in thread.sleep and then it will wake up, then again the dialog will appearand it will show the button and so on and so forth. This loop is working fine with me, but the issue I am having is that after the first dialog appears and I click on the button to hide the main window, the second time the main window appears, the button would appear as a "pressed" button, not as a new button. I think it's because I "pressed" on it the first time the main window appeared. And it stays like that until I stop the program and run it again.
So my question is, any idea how I can "reset" the button control? Or do I need to reset the mouse click event? Any pointers on this would be helpful.
You should run the loop on a background thread. If you run it on the UI thread, the application won't be able to respond to user input.
The easiest and recommended way to run some code on a background thread is to start a new Task.
Also note that you cannot access the window from a background thread so you need to use the dispatcher to marshal the call back to the UI thread.
The following sample code should give you the idea.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
while (true)
{
Dispatcher.Invoke(() => callmyfunction());
System.Threading.Thread.Sleep(5000);
}
}, TaskCreationOptions.LongRunning);
}
public void callmyfunction()
{
WindowState = WindowState.Normal;
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
}

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 :))

Hide WPF Window Until Fully Loaded

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.

Categories