简体   繁体   中英

How can I make a good splash screen that does two actions at once?

I'm currently trying to make a splash screen, however, I can't seem to be able to make a few tasks setup things at once.

I've tried using the BackgroundWorker class, as well as the Thread class, and none seem to work.

In the App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    var splashScreen = new Windows.Splash();
    splashScreen.Show();

    base.OnStartup(e);

    splashScreen.Close();
}

In the splashScreen.xaml.cs:

public Splash()
{
    InitializeComponent();
    DataContext = this;

    changeLoadingTxtTimer = new System.Timers.Timer(2000);
    changeLoadingTxtTimer.Elapsed += Timer_Elapsed;

    backgroundWorker = new BackgroundWorker();
    backgroundWorker.DoWork += D_DoWork;
    backgroundWorker.RunWorkerAsync();

    changeLoadingTxtTimer.Start();
}

private void D_DoWork(object sender, DoWorkEventArgs e) { UpdateDatabase(); }

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    LoadingTxtValue = LoadingTxts[rd.Next(0, LoadingTxts.Length - 1)];

    if (!backgroundWorker.IsBusy)
        changeLoadingTxtTimer.Stop();
    }
}

I expect that as the BackgroundWorker works, the loading text will change every 2 seconds, but what actually happens is that the BackgroundWorker finishes its job, and the splash screen closes.

App.xaml

Remove the StartupUri entry

<Application
      x:Class="WpfSplashApp.App"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="clr-namespace:WpfSplashApp">
    <Application.Resources />
</Application>

App.xaml.cs

public partial class App : Application
{
    public App()
    {
        Startup += App_Startup;
    }

    private async void App_Startup( object sender, StartupEventArgs e )
    {
        var splash = new SplashWindow();
        splash.Show();

        await InitializeAsync();

        var main = new MainWindow();
        main.Show();
        MainWindow = main;

        splash.Close();            
    }

    private Task InitializeAsync()
    {
        // Do some ASYNC initialization 
        return Task.Delay( 5000 );
    }
}

If I understand correctly, you have a list of strings:

var TextList = new[] {"Text 1", "Text 2", "Text 3"};

And while a background job is happening, you want those strings to show up every 2 seconds. I have no idea about what your background worker does, but I'll assume you know what you're doing with it. I also assume your Textblock is bound to a string property called LoadingTxtValue on your your control.

The best tool in my opinion for this job is Reactive . Add a reference to System.Reactive , and use the following right after RunWorkerAsync .

Observable.Timer(TimeSpan.FromSeconds(2))
.Subscribe(
    t => App.Current.Dispatcher.Invoke(new Action(() => LoadingTxtValue = TextList[t])));

I hope this can solve your problem.

I think you should do the initialization of the main view inside the main view itself. Once the main view is initialized, it would raise a corresponding event. You then react to this event by closing the splash screen and showing the main view. So the only task of the splash screen is to display the splash content.

App.xaml.cs:

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    this.splashScreen = new Windows.Splash();
    this.splashScreen.Show();

    // Initialize the main application view
    this.MainWindow = new MainWindow();
    this.MainWindow.Initialized += ShowMainWindow;
    this.MainWindow.Initialize();
}

private void ShowMainWindow(object sender, EventArgs e)
{
    this.splashScreen.CloseSplashScreen();
    this.MainWindow.Show();
}

Splash.xaml.cs:

public Splash()
{
    InitializeComponent();
    this.DataContext = this;

    this.changeLoadingTxtTimer = new System.Timers.Timer(2000);
    this.changeLoadingTxtTimer.Elapsed += Timer_Elapsed;
    this.changeLoadingTxtTimer.Start();
}

public void CloseSplashScreen()
{
    this.changeLoadingTxtTimer.Stop();
    this.changeLoadingTxtTimer.Dispose();
    Close();
}

private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    this.Dispatcher.Invoke(() => this.LoadingTxtValue = this.LoadingTxts[rd.Next(0, this.LoadingTxts.Length - 1)]);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM