Pull to refresh

Создание заставок (splash screen) в .net 3.5 SP1

.NET *
Если вы сталкивались с программированием в .net, то наверняка замечали, что при запуске программы, написанной с использованием WPF, долгое время ничего не происходит. Так продолжается секунд 10, а потом уже открывается главное окно приложения. Даже запуск пустого шаблона WPF приложения занимает около двух секунд.

Эта пауза вносит неопределенность в восприятие программы пользователем: запустилась программа или нет?

Решить эту проблему можно показав заставку сразу после запуска. Это даст физический отклик сразу после запуска приложения и создаст иллюзию более быстрой загрузки.

О том, как это сделать написано под катом.

Почему приложение так долго загружается



Это происходит из-за того, что при запуске 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. Спасибо.

Tags:
Hubs:
Total votes 62: ↑58 and ↓4 +54
Views 21K
Comments Comments 67