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

发布于 2024-11-16 15:56:01 字数 1123 浏览 7 评论 0原文

我需要在应用程序启动后 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() 代码相当难看,但无法设计出更简洁的替代方案。我在这里缺少一个常见的习语吗?

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

I have an action I need to perform around 3 seconds after my app starts. I've implemented it as follows:

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

I find the StartApp() code rather ugly but have not been able to concoct a neater alternative. Is there a common idiom I'm missing here?

PS. Yes, I'm aware SplashScreen has an auto-close option. I'm not wanting to use that mainly because it begins closing as soon as the app has loaded, which I don't want to do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

等风来 2024-11-23 15:56:01

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

如何我们在 WPF 应用程序中进行空闲时间处理?

这并不完全是您想要的,因为一旦您的应用程序空闲,它就会关闭您的窗口,但您可能会考虑在应用程序空闲后开始延迟。您可能会发现该链接很有帮助。

Here is something similar you might be interested in:

How do we do idle time processing in WPF application?

It's not exactly what you are looking for, because it will close your window as soon as your app goes idle, but you might consider to start your delay after your app went idle. You might find that link helpful than.

哽咽笑 2024-11-23 15:56:01

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

Do you not have a specific state when your application is done starting? Normally you want your SplashScreen to close when your application is ready to handle user input, instead of an arbitrary 3 secs. So I would suggest to close your SplashScreen then.

蓝天 2024-11-23 15:56:01

这是我能想到的最好的办法:

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()静态,因此任何扩展方法实际上都不会针对其调用的 Dispatcher 执行。 YMMV。

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

This is about the best I could come up with:

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

I toyed with extension methods for Dispatcher, but ultimately found them less intuitive. That's because PushFrame() is static, so any extension methods don't actually execute against the Dispatcher they're invoked against. YMMV.

Note that you could also call app.Run() instead of PumpDispatcherUntilAppExit(), but I just did that for consistency.

童话 2024-11-23 15:56:01

如果它丑陋并不重要,您可以将其重构为采用

正如丑陋一样,您可能意味着它看起来像糟糕的代码,我建议使用普通线程(在操作之前使用Thread.Sleep),它使用Dispatcher.Invoke 反而。不过,我不知道这方面有任何最佳实践。这也可以很好地重构为采用 Action 的简单方法。

如果您想要非阻塞等待也可以找到一个关于此的问题

Does not really matter if it is ugly, you can just refactor it into a method which takes an Action as parameter for example and that won't be much of a problem.

As by ugly you probably meant that it looks like bad code i would suggest the use of a normal thread (with Thread.Sleep before your action) which uses Dispatcher.Invoke instead. I for one am not aware of any best practice regarding this though. This can also be nicely refactored into a simple method taking an Action.

If you want a non-blocking wait there is a question to be found about that as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文