简体   繁体   中英

Wait until the Splashscreen is visible without blocking the UI thread

following situation: I got a splashscreen which has to fade in over 2 seconds (from transparent to opaque). While the window nicely fades in, the program should wait until it is fully visible (the Storyboard finished) and then it should continue doing it's stuff. While the window is fading in, the user should already see the animations of the control (so blocking the UI thread is not an option, of course). And with animations I mean the loading circle which spins happily.

After I found a nice variant of how to fade in and out a window with WPF's storyboards, I tried to accomplish this by using the EventWaitHandle. As my intialization routine already runs asynchronous I was able to use it. This blocked the worker thread and stopped my application doing the initialization stuff before the Splashscreen was fully visible. But somehow this has been broken after a while and it doesn't seem to be the best solution.

Here's how I'm doing it, currently:

public async Task Appear(double time)
{
    Core.IDE.GetGUICore().GetUIDispatcher().Invoke(() =>
    {
        this.Opacity = 0;
        this.Show();

        _fadeInStoryboard = new Storyboard();
        _fadeInStoryboard.Completed += this.FadeInAnimation;
        DoubleAnimation fadeInAnimation = new DoubleAnimation(0.0, 1.0, new Duration(TimeSpan.FromSeconds(time)));
        Storyboard.SetTarget(fadeInAnimation, this);
        Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath(OpacityProperty));
        _fadeInStoryboard.Children.Add(fadeInAnimation);
    });

    _currentHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
    Core.IDE.GetGUICore()
        .GetUIDispatcher()
        .InvokeAsync(this._fadeInStoryboard.Begin, DispatcherPriority.Render);
    _currentHandle.WaitOne();
}

/// <summary>
/// Hides the SplashScreen with a fade-out animation.
/// </summary>
/// <param name="time">The fade-out time in seconds.</param>
public void Disappear(double time)
{
    Core.IDE.GetGUICore().GetUIDispatcher().Invoke(() =>
    {
        _fadeOutStoryboard = new Storyboard();
        _fadeOutStoryboard.Completed += this.FadeOutAnimation;
        DoubleAnimation fadeOutAnimation = new DoubleAnimation(1.0, 0.0,
            new Duration(TimeSpan.FromSeconds(time)));
        Storyboard.SetTarget(fadeOutAnimation, this);
        Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath(OpacityProperty));
        _fadeOutStoryboard.Children.Add(fadeOutAnimation);
    });

    Core.IDE.GetGUICore()
       .GetUIDispatcher()
       .BeginInvoke(new Action(_fadeOutStoryboard.Begin), DispatcherPriority.Render, null);
}

private void FadeInAnimation(object sender, EventArgs e)
{
    _currentHandle.Set();
}

private void FadeOutAnimation(object sender, EventArgs e)
{
    this.Hide();
}

Is this the right approach? Any better solutions? Any ideas why it is broken? By the way, with broken I mean that the application continues doing its initialization stuff whilst the window is fading in, which ends in an animation which runs until it's probably at 30% visibility and then fading out because the main window already showed up.

Thanks in advance

If you declare your Storyboard in XAML, it really will simplify things for you. Try using this Trigger in your splash screen control:

<Grid>
    <Grid.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard Duration="0:0:5" Completed="Storyboard_Completed">
                    <DoubleAnimation From="0.0" To="1.0" 
                        Storyboard.TargetProperty="Opacity" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Grid.Triggers>
    <!--Put your UI elements here-->
</Grid>

You can load the rest of your app from the Storyboard_Completed handler, or if this is in a separate Window , then you can raise some event or delegate from there, which you should handle in the MainWindow .

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