WPF (C#) Splash экран прогресса загрузки в отдельном потоке

442
07 марта 2017, 13:16

Имеется приложение. Первый запуск. Авторизация.

Основное окно понимает, что нет сохранённых данных и выдаёт окно авторизации. Основное окно при этом ещё даже не отобразилось.

После ввода логина/пароля в форме авторизации, та отправляет запрос на сервер и получает токен.

Получив токен, второе окно закрывается и возвращает управление основному. Авторизация проходит за доли секунды.

Но после авторизации на сервер надо отправить повторный запрос для получения коллекции данных и в последствии занести их в БД. Всё это нужно сделать до отображения основной формы пользователю.

Этот запрос выполняется уже от 5 секунд и дольше, в зависимости от количества получаемых данных.

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

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

Основное окно нельзя отображать до получения данных, ибо вся им отображаемая информация будет браться из полученной по запросу информации. Без неё это голый шаблон, который пользователю видеть не нужно.

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

Как подобное правильно реализовать?

Дополнительная информация: при втором и следующих запусках программы, она будет брать данные авторизации из сохранённых свойств (Property.Settings.Default), а данные для отображения в основном окне будет брать из локального файлы БД, в который будут кэшироваться результаты запроса данных.

В последствии программа будет через определённый интервал запускать в отдельном потоке запрос на обновление данных в локальной БД и обновлении отображаемой в окне информации.

Answer 1

Смысла делать многопоточный UI обычно нету. Типичное WPF-приложение работает так: UI бежит в одном, главном потоке, VM (это объекты для отображения и бизнес-логика) — в том же самом главном потоке, модели (базы данных, сеть, вычисления) — в главном и фоновых потоках.

Для начала, нужно сделать так, чтобы в начале работы не показывалось главное окно автоматически. Для этого из App.xaml удаляем StartupUri="MainWindow.xaml".

Окей, что дальше? Дальше нам нужно показать окна в code-behind. Идём в App.xaml.cs и пишем следующее:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        var mainVM = new MainVM();
        var mainWindow = new MainWindow() { DataContext = mainVM };
        mainWindow.Show();    
    }
}

Это равносильный вариант, который показывает главное окно. Теперь добавим логику авторизации.

protected override async void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var mainVM = new MainVM();
    Window authorizationWindow = null;
    if (!mainVM.HasCredentials()) // нет авторизации?
    {
        // выдаём окно
        var authorizationVM = new AutorizationVM();
        authorizationWindow = new AutorizationWindow() { DataContext = authorizationVM };
        authorizationWindow.Show();
        await authorizationVM.RunAuthorization();
        // в этой точке у нас есть авторизация, скармливаем её в MainVM
        mainVM.SetCredentials(authorizationVM);
    }
    // теперь мы авторизованы, отправляем запрос данных
    // окно, которое отображает Splash
    var dataProgressWindow = new ProgressWindow() { DataContext = mainVM };
    dataProgressWindow.Show();
    // когда мы открыли новое окно, можно закрыть старое
    authorizationWindow?.Close(); // знак вопроса нужен, а то вдруг null
    // дожидаемся конца загрузки данных
    await mainVM.DownloadData();
    // тут мы готовы к работе, запускаем главное окно
    var mainWindow = new MainWindow() { DataContext = mainVM };
    mainWindow.Show();
    // а сплэш-скрин можно закрыть
    dataProgressWindow.Close();
    // я обычно для симметрии делаю ещё
    // await mainVM.Run(); mainWindow.Close();
    // но это не обязательно
}

Для этого вам придётся разделить логику и представление и немного подучить MVVM.

READ ALSO
Регулярные выражения C# Выборка текста

Регулярные выражения C# Выборка текста

Не могу составить правильно регулярное выражениеПомогите!

278
DependencyProperty типа IList - изменение коллекции

DependencyProperty типа IList - изменение коллекции

Есть некий UserControlУ него есть свойство зависимостей ItemsProperty типа IList<string> (да да, именно строго типизированный лист)

260
Запуск программ по расписанию через waitable timer C#

Запуск программ по расписанию через waitable timer C#

Я пишу курсовую запуск программ по расписанию на C#, тип проекта Windows FormsПреподаватель сказал реализовать через waitable timer

383
Какие ошибки не видит компилятор, но видит run-time?

Какие ошибки не видит компилятор, но видит run-time?

Проходил онлайн-собеседование и был предложен тест:

305