Как ускорить загрузку экрана-заставки

Я оптимизирую запуск приложения WinForms. Одной проблемой, которую я определил, является загрузка формы экрана-заставки. Это берет о половине секунды к секунде.

Я знаю, что многопоточность нет - нет на частях UI, однако, видя, как экран-заставка является довольно автономной частью приложения, это возможный так или иначе смягчить его производительность, пораженную путем броска его один некоторый другой поток (возможно, в способе, которым Chrome делает это), так, чтобы важные части приложения могли на самом деле начаться.

7
задан AngryHacker 25 March 2010 в 17:33
поделиться

5 ответов

.NET framework уже имеет очень хорошую поддержку экранов-заставок в приложениях Windows Forms. Посмотрите в этой ветке образец кода. Он действительно оптимизирован для горячего запуска, он обеспечивает запуск и работу заставки и экрана перед инициализацией основного приложения.

9
ответ дан 6 December 2019 в 11:47
поделиться

Нет никакой пользы от создания потока, если ваша цель - как можно быстрее поднять заставку.

Есть несколько способов создания заставок, и более сложный из них упомянут здесь , но это простой метод, который я использовал с полным успехом:

Просто убедитесь, что вы загрузили и показали сначала заполните форму , а затем продолжайте загружать приложение, пока пользователь смотрит на красивый экран-заставку. Когда основная форма завершает загрузку, она может закрыть заставку прямо перед тем, как она покажет себя (простой способ сделать это - передать форму заставки в основную форму в ее конструкторе):

static void Main()
{
    Application.SetCompatibleTextRenderingDefault(false);
    SplashForm splash = new SplashForm();
    splash.Show();
    splash.Refresh(); // make sure the splash draws itself properly
    Application.EnableVisualStyles();
    Application.Run(new MainForm(splash));
}

public partial class MainForm : Form
{
    SplashForm _splash;
    public MainForm(SplashForm splash)
    {
        _splash = splash;
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        // or do all expensive loading here (or in the constructor if you prefer)

        _splash.Close();
    }
}

Альтернатива: если вы предпочитаете не передавать заставку в MainForm (возможно, это кажется неэлегантным), затем подпишитесь на событие Load MainForm и закройте там экран-заставку:

static class Program
{
    static SplashForm _splash;

    [STAThread]
    static void Main()
    {
        Application.SetCompatibleTextRenderingDefault(false);
        _splash = new SplashForm();
        _splash.Show();
        _splash.Refresh();
        Application.EnableVisualStyles();
        MainForm mainForm = new MainForm();
        mainForm.Load += new EventHandler(mainForm_Load);
        Application.Run(mainForm);
    }

    static void mainForm_Load(object sender, EventArgs e)
    {
        _splash.Dispose();
    }
}

Как упоминалось в this thread , потенциальным недостатком этого решения является то, что пользователь не сможет взаимодействовать с заставкой. Однако обычно этого не требуется.

4
ответ дан 6 December 2019 в 11:47
поделиться

Многопоточность в WinForms - это нормально, пока весь пользовательский интерфейс находится в одном потоке.

Именно так обычно и делают заставки. Важная работа выполняется в фоновом потоке, в то время как окно-заставка отображается в потоке пользовательского интерфейса, чтобы пользователь знал, что остальная часть программы появится в ближайшее время.

После того, как произошло важное событие, вызовите событие, чтобы поток пользовательского интерфейса знал, что пора скрыть экран-заставку (просто не забудьте маршалировать обработчик событий, используя Invoke (), обратно в поток пользовательского интерфейса, чтобы закройте заставку).

1
ответ дан 6 December 2019 в 11:47
поделиться

Да.

Вам необходимо создать новый поток STA, который показывает экран-заставку, используя Application.Run , затем вызовите Close , используя Invoke , после того, как основная форма будет готова. (в основном потоке).

ИЗМЕНИТЬ : Например:

static SplashForm splash;

Thread splashThread = new Thread(delegate() {
    splash = new SplashForm();
    Application.Run(splash);        //Blocking call on separate thread    
});
splashThread.SetApartmentState(ApartmentState.STA)
splashThread.Start();

LoadApp();

//In MainForm_Shown:
splash.BeginInvoke(new Action(splash.Close));

Для оптимальной производительности вы должны сделать так, чтобы ваш метод Main отображал экран-заставку, а затем вызвал отдельный метод, загружающий приложение. Таким образом, все сборки будут загружены после отображения экрана-заставки. (Когда вы вызываете метод, JITter загружает все используемые им типы до того, как метод начнет выполняться)

1
ответ дан 6 December 2019 в 11:47
поделиться

Ответ действительно о восприятии. Существуют различные методы, NGEN и сборка, помещающие вещи в GAC, но вы должны понимать, что происходит на самом деле.

C # требуется время для загрузки виртуальной машины, загрузки ссылочных сборок и загрузки сборок в зависимости от того, что находится на этом экране-заставке. И тогда для запуска первого экрана еще требуется некоторое время из "холодного" старта.

Это из-за JIT-компиляции, которая происходит при первом доступе к экрану.

Я использую традиционную легкую страницу-заставку, которая загружается быстро и становится видимой, но в фоновом режиме я создаю поток и загружаю невидимую форму. В этой форме есть все элементы управления, которые я намереваюсь использовать, поэтому JIT-компилятор делает свое дело и загружает сборки. Это создает иллюзию отзывчивости с легкостью. Время, необходимое для запуска + видимой страницы-заставки + паузы + времени, чтобы щелкнуть 1-й вариант, больше, чем время, необходимое для выполнения потока, а затем очистки и выгрузки формы.

В противном случае приложения кажутся неуклюжими и медленными для пользователей при первом запуске. Горячий запуск экранов происходит намного быстрее, потому что сборка и JIT завершены.

1
ответ дан 6 December 2019 в 11:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: