在UI线程上实现延迟操作的最简洁方法

时间:2011-06-22 13:42:44

标签: wpf splash-screen dispatcher

我有一个动作,我需要在应用程序启动后大约3秒钟执行。我按如下方式实现了它:

internal static class Entry
{
    private static SplashScreen splashScreen;

    [STAThread]
    internal static void Main()
    {
        ShowSplashScreen();
        StartApp();
    }

    private static void ShowSplashScreen()
    {
        splashScreen = new SplashScreen("Splash.png");
        splashScreen.Show(false, true);
    }

    private static void StartApp()
    {
        var app = new App();

        //this, in particular, is ugly and more difficult to comprehend than I'd like
        var dispatcherTimer = new DispatcherTimer();
        dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
        dispatcherTimer.Tick += delegate
        {
            CloseSplashScreen();
            dispatcherTimer.Stop();
        };
        dispatcherTimer.Start();

        app.Run();
    }

    private static void CloseSplashScreen()
    {
        splashScreen.Close(TimeSpan.FromSeconds(1));
    }
}

我发现StartApp()代码相当丑陋,但却无法编造一个更整洁的替代品。我在这里找不到一个常见的习语吗?

PS。是的,我知道SplashScreen有一个自动关闭选项。我不想使用它主要是因为它一旦应用程序加载就开始关闭,我不想这样做。

4 个答案:

答案 0 :(得分:0)

如果它是丑陋的并不重要,你可以将它重构为一个方法,例如以Action作为参数,这不会是一个大问题。

通过丑陋你可能意味着它看起来像坏代码我会建议使用普通线程(在你的行动之前使用Thread.Sleep)而使用Dispatcher.Invoke代替。我个人并不知道有任何关于此的最佳做法。这也可以很好地重构为一个采用Action的简单方法。

如果您想要找到非阻塞等待there is a question,也可以找到它。

答案 1 :(得分:0)

以下是您可能感兴趣的类似内容:

How do we do idle time processing in WPF application?

这并不是您正在寻找的,因为它会在您的应用程序空闲时关闭您的窗口,但您可能会考虑在应用程序空闲后开始延迟。您可能会发现该链接比。

更有帮助

答案 2 :(得分:0)

启动应用程序时,您是否没有特定的状态?通常,当应用程序准备好处理用户输入时,您希望SplashScreen关闭,而不是任意3秒。所以我建议关闭你的SplashScreen。

答案 3 :(得分:0)

这是我能想到的最好的结果:

internal static class Entry
{
    private static SplashScreen splashScreen;
    private static App app;

    [STAThread]
    internal static void Main()
    {
        ShowSplashScreen();
        CreateApp();
        PumpDispatcherUntilPriority(DispatcherPriority.Loaded);
        PumpDispatcherFor(TimeSpan.FromSeconds(2));
        CloseSplashScreen();
        PumpDispatcherUntilAppExit();
    }

    private static void ShowSplashScreen()
    {
        splashScreen = new SplashScreen("Splash.png");
        splashScreen.Show(false, true);
    }

    private static void CloseSplashScreen()
    {
        splashScreen.Close(TimeSpan.FromSeconds(0.5));
    }

    private static void CreateApp()
    {
        app = new App();
    }

    private static void PumpDispatcherUntilPriority(DispatcherPriority dispatcherPriority)
    {
        var dispatcherFrame = new DispatcherFrame();
        Dispatcher.CurrentDispatcher.BeginInvoke((ThreadStart)(() => dispatcherFrame.Continue = false), dispatcherPriority);
        Dispatcher.PushFrame(dispatcherFrame);
    }

    private static void PumpDispatcherFor(TimeSpan timeSpan)
    {
        var dispatcherFrame = new DispatcherFrame();

        using (var timer = new Timer(o => dispatcherFrame.Continue = false, null, (long)timeSpan.TotalMilliseconds, Timeout.Infinite))
        {
            Dispatcher.PushFrame(dispatcherFrame);
        }
    }

    private static void PumpDispatcherUntilAppExit()
    {
        var dispatcherFrame = new DispatcherFrame();
        app.Exit += delegate
        {
            dispatcherFrame.Continue = false;
        };
        Dispatcher.PushFrame(dispatcherFrame);
    }
}

我玩弄Dispatcher的扩展方法,但最终发现它们不太直观。这是因为PushFrame()static,因此任何扩展方法实际上都不会针对它们被调用的Dispatcher执行。 YMMV。

请注意,您也可以拨打app.Run()而不是PumpDispatcherUntilAppExit(),但我只是为了保持一致而这样做。