Если вы сталкивались с программированием в .net, то наверняка замечали, что при запуске программы, написанной с использованием WPF, долгое время ничего не происходит. Так продолжается секунд 10, а потом уже открывается главное окно приложения. Даже запуск пустого шаблона WPF приложения занимает около двух секунд.
Эта пауза вносит неопределенность в восприятие программы пользователем: запустилась программа или нет?
Решить эту проблему можно показав заставку сразу после запуска. Это даст физический отклик сразу после запуска приложения и создаст иллюзию более быстрой загрузки.
О том, как это сделать написано под катом.
Это происходит из-за того, что при запуске Windows библиотеки .net, которые занимают порядка 20 мегабайт, не загружаются в память. .net Framework динамически подгружает необходимые библиотеки при запуске программы. Если мы посмотрим Output в студии при запуске программы, то сможем это увидеть:
Нужно было плясать с бубном и запускать native код до начала запуска приложения. А потом его как-то останавливать. Коммерческий компонент Quicksplash предлагает удалять файл из заданной папки после загрузки вашего приложения. Вариант несколько неудобный. Остальные и того хуже.
С появлением .net 3.5 sp1 все делается буквально двумя щелчками мыши. Поддерживаются только изображения следующих форматов: BMP, GIF, JPEG, PNG и TIFF. В PNG есть поддержка альфа-канала.
Самый простой вариант. Он достаточен в 99% случаев. Для создания заставки необходимо добавить изображение в проект:
И в окне Properties добавленного файла установить параметру Build Action значение SplashScreen.
Это все, что необходимо.
Во время сборки в файл App.g.cs добавятся следующие строки:
Их мы разберем чуть позже.
Второй вариант мало чем отличается от первого: просто мы все сделаем своими руками. Для этого добавляем картинку к проекту. Открываем App.xaml (не App.xaml.cs) и добавляем новый обработчик для события StartUp:
Переходим в файл App.xaml.cs, ищем только что созданный метод и дополняем его следующими строчками:
Давайте их разберем. В первой строке происходит создание нового экземпляра класса SplashScreen. Конструктор имеет единственный параметр — имя файла:
Во второй строке мы вызываем метод Show(bool autoClose). Если значение аргумента истинно, то заставка закроется автоматически после загрузки приложениея. В противном случае необходимо вызвать метод Close.
Практика показала, что бывают ситуации, когда необходимо показывать заставку не только при загрузке, но и, например, сразу после окна авторизации:
Из-за того, что InitializeComponent() вызывается после авторизации, происходит дополнительная загрузка библиотек, которые используются в коде основного приложения, но не используются в окне авторизации. Это приводит к задержке перед появлением основного окна. Для того, чтобы избежать этого эффекта можно поступить следующим образом:
Здесь единственная новая строчка:
Метод Close() закрывает заставку с эффектом затухания. В качестве параметра метод принимает интервал времени, в течение которого будет «гаснуть» заставка.
В процессе использование пару раз проскакивал черный фон вместо прозрачности. Причин пока не выявил.
Возникает Win32Exeption при переключении на другое приложение в тот момент, когда заставка гаснет. Можно поймать окружив метод Close() блоком try...catch.
Использование заставки в вашей программе делает ее более уютной и человечной по отношению к пользователю. Позволяет избежать лишней ментальной агрессии по отношению к разработчику. :-)
UPD: Это относится только к WPF приложениям.
UPD2: Переместил в блог .NET. Спасибо.
Эта пауза вносит неопределенность в восприятие программы пользователем: запустилась программа или нет?
Решить эту проблему можно показав заставку сразу после запуска. Это даст физический отклик сразу после запуска приложения и создаст иллюзию более быстрой загрузки.
О том, как это сделать написано под катом.
Почему приложение так долго загружается
Это происходит из-за того, что при запуске Windows библиотеки .net, которые занимают порядка 20 мегабайт, не загружаются в память. .net Framework динамически подгружает необходимые библиотеки при запуске программы. Если мы посмотрим Output в студии при запуске программы, то сможем это увидеть:
'SplashDemo.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'SplashDemo.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.HostingProcess.Utilities\9.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.HostingProcess.Utilities.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'SplashDemo.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_MSIL\PresentationFramework\3.0.0.0__31bf3856ad364e35\PresentationFramework.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
…
…
…
'SplashDemo.vshost.exe' (Managed): Loaded 'D:\work\Visual Studio 2008\Projects\SplashDemo\bin\Debug\SplashDemo.exe', Symbols loaded.
Step into: Stepping over non-user code 'System.Windows.SplashScreen.SplashScreen'
Step into: Stepping over non-user code 'SplashDemo.App.App'
'SplashDemo.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Step into: Stepping over non-user code 'SplashDemo.App.InitializeComponent'
'SplashDemo.vshost.exe' (Managed): Loaded 'C:\Windows\assembly\GAC_MSIL\PresentationFramework.Aero\3.0.0.0__31bf3856ad364e35\PresentationFramework.Aero.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Как это решалось раньше
Нужно было плясать с бубном и запускать native код до начала запуска приложения. А потом его как-то останавливать. Коммерческий компонент Quicksplash предлагает удалять файл из заданной папки после загрузки вашего приложения. Вариант несколько неудобный. Остальные и того хуже.
Как это решается теперь
С появлением .net 3.5 sp1 все делается буквально двумя щелчками мыши. Поддерживаются только изображения следующих форматов: BMP, GIF, JPEG, PNG и TIFF. В PNG есть поддержка альфа-канала.
Вариант №1
Самый простой вариант. Он достаточен в 99% случаев. Для создания заставки необходимо добавить изображение в проект:
И в окне Properties добавленного файла установить параметру Build Action значение SplashScreen.
Это все, что необходимо.
Во время сборки в файл App.g.cs добавятся следующие строки:
SplashScreen splashScreen = new SplashScreen("splash.png");
splashScreen.Show(true);
* This source code was highlighted with Source Code Highlighter.
Их мы разберем чуть позже.
Вариант №2а
Второй вариант мало чем отличается от первого: просто мы все сделаем своими руками. Для этого добавляем картинку к проекту. Открываем App.xaml (не App.xaml.cs) и добавляем новый обработчик для события StartUp:
Переходим в файл App.xaml.cs, ищем только что созданный метод и дополняем его следующими строчками:
private void AppStartUp(object sender, StartupEventArgs e)
{
var splash = new SplashScreen("splash.png");
splash.Show(true);
}
* This source code was highlighted with Source Code Highlighter.
Давайте их разберем. В первой строке происходит создание нового экземпляра класса SplashScreen. Конструктор имеет единственный параметр — имя файла:
var splash = new SplashScreen("splash.png");
* This source code was highlighted with Source Code Highlighter.
Во второй строке мы вызываем метод Show(bool autoClose). Если значение аргумента истинно, то заставка закроется автоматически после загрузки приложениея. В противном случае необходимо вызвать метод Close.
splash.Show(true);
* This source code was highlighted with Source Code Highlighter.
Вариант №2б
Практика показала, что бывают ситуации, когда необходимо показывать заставку не только при загрузке, но и, например, сразу после окна авторизации:
public Window1()
{
ShowAuthorizationDialog();
InitializeComponent();
}
* This source code was highlighted with Source Code Highlighter.
Из-за того, что InitializeComponent() вызывается после авторизации, происходит дополнительная загрузка библиотек, которые используются в коде основного приложения, но не используются в окне авторизации. Это приводит к задержке перед появлением основного окна. Для того, чтобы избежать этого эффекта можно поступить следующим образом:
public Window1()
{
ShowAuthorizationDialog();
var splash = new SplashScreen("spalsh.png");
splash.Show(false);
InitializeComponent();
splash.Close(TimeSpan.FromMinutes(0.5));
}
* This source code was highlighted with Source Code Highlighter.
Здесь единственная новая строчка:
splash.Close(TimeSpan.FromMinutes(0.5));
* This source code was highlighted with Source Code Highlighter.
Метод Close() закрывает заставку с эффектом затухания. В качестве параметра метод принимает интервал времени, в течение которого будет «гаснуть» заставка.
Известные баги
В процессе использование пару раз проскакивал черный фон вместо прозрачности. Причин пока не выявил.
Возникает Win32Exeption при переключении на другое приложение в тот момент, когда заставка гаснет. Можно поймать окружив метод Close() блоком try...catch.
Заключение
Использование заставки в вашей программе делает ее более уютной и человечной по отношению к пользователю. Позволяет избежать лишней ментальной агрессии по отношению к разработчику. :-)
UPD: Это относится только к WPF приложениям.
UPD2: Переместил в блог .NET. Спасибо.