Анимированная заставка с использованием Caliburn.Micro - PullRequest
1 голос
/ 26 сентября 2019

Я создаю приложение, используя Caliburn.Micro.Приложение связывается с API во время запуска, поэтому мне нужно показать Splashscreen пользователям.Я создал свой собственный анимированный экран-заставку в виде окна, которое активируется из начальной загрузки в методе OnStartup.Процесс запуска управляется моделью представления splashscreens.

Когда все процессы, связанные с запуском, завершены, как я могу сказать загрузчику закрыть заставку и активировать другое окно?

Я думал о создании событияно я не могу подписать загрузчик на IEventaggregator.

Я попытался отобразить Splashscreen внутри contentcontrol в ShellView и просто переключиться на другой vm после завершения загрузки.Проблема здесь в том, что заставка должна отображаться в прозрачном окне без полей, которое нельзя изменить после создания окна.

public class Bootstrapper : BootstrapperBase
    {
        private SimpleContainer _container = new SimpleContainer();

        public Bootstrapper()
        {
            Initialize();
        }

        protected override void Configure()
        {
            _container
                .Singleton<IWindowManager, WindowManager>()
                .Singleton<IEventAggregator, EventAggregator>();

            GetType().Assembly.GetTypes()
                .Where(type => type.IsClass)
                .Where(type => type.Name.EndsWith("ViewModel"))
                .ToList()
                .ForEach(viewModelType => _container.RegisterPerRequest(
                    viewModelType, viewModelType.ToString(), viewModelType));
        }

        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement),
                new FrameworkPropertyMetadata(
                    XmlLanguage.GetLanguage(
                        CultureInfo.CurrentCulture.IetfLanguageTag
                        )
                    )
                );
            DisplayRootViewFor<AnimatedSplashViewModel>();
            //DisplayRootViewFor<ShellViewModel>();
        }


        protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }
    }
 public class AnimatedSplashViewModel : Screen
    {
        private IEventAggregator _events;

        private string _splashMessage;

        public string SplashMessage
        {
            get { return _splashMessage; }
            set
            {
                _splashMessage = value;
                NotifyOfPropertyChange(() => SplashMessage);
            }
        }

        public AnimatedSplashViewModel(IEventAggregator events)
        {
            _events = events;
            SplashMessage = "Please wait";

            // Simulation of long tasks
            var worker = new BackgroundWorker();
            worker.DoWork += Worker_DoWork;
            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
            worker.RunWorkerAsync();


        }

        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _events.PublishOnUIThread(new SplashFinishedEvent());
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            Thread.Sleep(10000);
        }
    }

Ответы [ 2 ]

1 голос
/ 26 сентября 2019

Вы должны либо использовать ShellViewModel для корневого представления и заменить представление заставки на "основное" представление, либо вы можете просто подождать, чтобы отобразить корневое представление, пока заставка не будет закрыта:

protected override void OnStartup(object sender, StartupEventArgs e)
{
    Application.ShutdownMode = ShutdownMode.OnExplicitShutdown;

    var windowManager = IoC.Get<IWindowManager>();
    var eventAggregator = IoC.Get<IEventAggregator>();
    windowManager.ShowDialog(new AnimatedSplashViewModel(eventAggregator));
    DisplayRootViewFor(typeof(ShellViewModel));
}

...
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    TryClose();
}
0 голосов
/ 30 сентября 2019

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

Сначала я использовал WindowManager для создания диалогового окна Splashscreen и позволяю SplashscreenViewModel выполнять всю работу.

Оказалось, что этот подход требуетвозраст для загрузки.Поэтому, когда я попытался выполнить это, потребовалось около 8 секунд, чтобы появился Dailog.Это слишком долго для моих нетерпеливых пользователей.Я думаю, это произошло потому, что я использовал IoC для введения большого количества зависимостей в SplashscreenViewModel.

windowManager.ShowDialog(new AnimatedSplashViewModel(locationEndpoint, userEndpoint, applicationEndpoint, adUser, clientInfo, locationInfo, loggedInUser));

Второй подход заключался в создании Splashscreen в качестве диалога и использовании BackgroundWorker для всех вычислений и API-интерфейсов внутри Bootstrapper.,Хотя это работало довольно быстро, я чувствовал, что должен быть лучший подход.

Третье и окончательное решение: Bootstrapper вызывает ShellViewModel.

 public Bootstrapper()
    {
        Initialize();
        DisplayRootViewFor<ShellViewModel>();
    }

В методе OnInitialize, который я создалBackgroundWorker, который выполняет все длительные задачи при отображении SplashScreen в виде диалога с помощью WindowManager.

protected override void OnInitialize()
    {
        var windowManager = new WindowManager();
        using (BackgroundWorker bw = new BackgroundWorker())
        {
            bw.DoWork += InitializeApplication;
            bw.RunWorkerCompleted += InitializationCompleted;
            bw.RunWorkerAsync();
            windowManager.ShowDialog(new AnimatedSplashViewModel(_events));
        }
    }

Теперь для AnimatedSplashscreenViewModel требуется только одна зависимость - EventAggregator.Я позволил ему обрабатывать пользовательское событие с именем SplashMessageChangedEvent.

public class SplashMessageChangedEvent
{
    public string Content { get; set; }
    public bool CloseDialog { get; set; } = false;

    public SplashMessageChangedEvent(string content)
    {
        Content = content;
    }

    public SplashMessageChangedEvent(bool closeDialog)
    {
        CloseDialog = closeDialog;
    }
}

В событии InitializationCompleted в ShellViewModel я публикую следующее событие, чтобы закрыть диалог:

private void InitializationCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        _events.PublishOnUIThread(new SplashMessageChangedEvent(true));
    }

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

...