【问题标题】:Wait until the Splashscreen is visible without blocking the UI thread等到 Splashscreen 可见而不阻塞 UI 线程
【发布时间】:2014-06-22 20:32:00
【问题描述】:

以下情况:我得到了一个闪屏,它必须在 2 秒内淡出(从透明到不透明)。当窗口很好地淡入时,程序应该等到它完全可见(故事板完成),然后它应该继续做它的东西。当窗口淡入时,用户应该已经看到了控件的动画(当然,阻止 UI 线程不是一种选择)。对于动画,我指的是快乐旋转的加载圈。

在我找到了如何使用 WPF 的情节提要淡入和淡出窗口的一个很好的变体之后,我尝试使用 EventWaitHandle 来完成此操作。由于我的初始化例程已经异步运行,我可以使用它。这阻止了工作线程并在 Splashscreen 完全可见之前停止了我的应用程序执行初始化工作。但不知何故,这在一段时间后就被打破了,这似乎不是最好的解决方案。

这是我目前的做法:

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

这是正确的方法吗?有更好的解决方案吗?任何想法为什么它被打破? 顺便说一句,破碎的意思是应用程序在窗口淡入时继续执行其初始化工作,最终以动画结束,该动画一直运行到它可能处于 30% 的可见度,然后因为主窗口已经出现而淡出。

提前致谢

【问题讨论】:

    标签: c# wpf multithreading storyboard splash-screen


    【解决方案1】:

    如果您在 XAML 中声明您的 Storyboard,它确实会为您简化事情。尝试在初始屏幕控件中使用此 Trigger

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

    您可以从Storyboard_Completed 处理程序加载应用程序的其余部分,或者如果这是在单独的Window 中,那么您可以从那里引发一些事件或delegate,您应该在@987654328 中处理这些事件@。

    【讨论】:

    • 谢谢,但这不起作用。在初始化我的应用程序的类中,我想调用“Appear”或类似的东西。然后 Splashscreen 应该淡入,同时初始化方法应该等到它完全可见。然后它应该继续。我不想使用事件。这意味着我必须在这个事件的处理程序中继续初始化,这使得(已经很长的)初始化例程的可读性降低。我使用的方法已经奏效了,但同时它不再...
    • 也许您应该考虑以不同的方式做事。看看我对How to open a child Window like a splash screen before MainWindow in WPF? 问题的回答。您可以使用App_Startup 方法轻松地将您的Completed 处理程序添加到App.xaml.cs 文件中。
    • ...代替该答案中的DispatcherTimer
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多