使用Caliburn.Micro的动画启动画面



我正在使用Caliburn.Micro创建一个应用程序。应用程序在启动期间与 api 通信,这就是我需要向用户显示启动画面的原因。我已经创建了自己的动画启动画面作为窗口,该窗口从 OnStartup 方法中的引导程序激活。 启动过程由初始屏幕视图模型管理。

当所有与启动相关的进程完成后,如何告诉引导程序关闭初始屏幕并激活另一个窗口?

我想过引发一个事件,但我无法将引导程序订阅到 IEventagregerator。

我尝试在 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);
}
}

您应该对根视图使用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();
}

我的情况是有人想知道最终的解决方案:

首先,我使用窗口管理器创建初始屏幕的对话框,并让SplashscreenViewModel完成所有工作。

事实证明,这种方法需要很长时间才能加载。因此,当我尝试执行时,Dailog 大约需要 8 秒才能出现。对于我不耐烦的用户来说,这太长了。 我认为这是因为我使用 IoC 将大量依赖项注入到SplashscreenViewModel中。

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

第二种方法是将启动画面创建为对话框,并使用 BackgroundWorker 来处理引导程序中的所有计算和 API 内容。 虽然这工作得很快,但我觉得一定有更好的方法。

第三个也是最后一个解决方案: Bootstrapper调用ShellViewModel。

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

在 OnInitialize 方法中,我创建了一个 BackgroundWorker 来执行所有长时间运行的任务,同时使用 WindowManager 将 SplashScreen 显示为对话框。

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;
}
}

在 ShellViewModel 的 InitializationDone 事件中,我发布以下事件以关闭对话框:

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

现在,这最后一种方法比其他两种方法快得多。 启动可执行文件后,初始屏幕会立即显示。

最新更新