在UI线程上运行代码,但在当前线程上调用回调?

4

我正在编写一个Windows 10通用应用程序。我需要在UI线程上运行一些特定的代码,但是一旦该代码完成,我希望在最初调用请求的同一线程上运行一些代码。请参见下面的示例:

    private static async void RunOnUIThread(Action callback)
    {
        //<---- Currently NOT on the UI-thread

        await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        {
            //Do some UI-code that must be run on the UI thread.
            //When this code finishes: 
            //I want to invoke the callback on the thread that invoked the method RunOnUIThread
            //callback() //Run this on the thread that first called RunOnUIThread()
        });
    }

我该如何实现这个呢?

2
它必须是相同的线程吗?还是可以是任何非 UI 线程池线程? - Scott Chamberlain
其实不太确定。调用这段代码的线程是从Unity中调用的,它运行在自己的线程上(据我所知),不确定它是否能正常工作。但如果您给我一个例子,我可以尝试一下! :) - Whyser
1
如果你正在使用 async void请不要这样做!,要么让你的方法返回 async Task,要么不要使用异步方法。 - Scott Chamberlain
1个回答

6

只需在await Dispatcher.RunAsync之后调用回调函数:

private static async void RunOnUIThread(Action callback)
{
    //<---- Currently NOT on the UI-thread

    await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Do some UI-code that must be run on the UI thread.
    });

    callback();
}

回调函数将在线程池中的工作线程上调用(不一定是与RunOnUIThread开始的相同线程,但您可能不需要那个)。

如果您真的希望在同一线程上调用回调函数,那么不幸的是会有些麻烦,因为工作线程没有同步上下文(允许您在特定线程上调用代码的机制)。因此,您必须同步调用Dispatcher.RunAsync以确保保持在同一线程上:

private static void RunOnUIThread(Action callback)
{
    //<---- Currently NOT on the UI-thread

    Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        //Do some UI-code that must be run on the UI thread.
    }).GetResults();

    callback();
}

注意:不要在UI线程中调用GetResults,这会导致您的应用程序死锁。在工作线程中,某些情况下可以接受,因为没有同步上下文,所以不会死锁。


谢谢Thomas,我为什么需要GetResults()函数? - Whyser
@user2422321,“GetResults()”将会阻塞,直到操作完成。如果你不调用它,它将会在后台继续进行,并且你将在UI线程的操作完成之前调用“callback()”。 - Thomas Levesque
正如你所猜测的那样,我似乎不需要GetResults()。感谢你的帮助! - Whyser
@user2422321,我并没有说你不需要GetResults()...如果你想在调用回调之前等待UI操作完成,那么你确实需要它。但是我忘记了,如果IAsyncAction还没有完成,你不能只是调用GetResults()...一个解决方法是使用Task.Run(() => Dispatcher.RunAsync(...)).Wait(),但这有点丑陋。 - Thomas Levesque
@user2422321,我认为您实际上并不需要在调用“RunOnUIThread”所在的同一线程上调用“callback”(因为很少有有效的原因想要这样做),但您只是不希望它在UI线程上执行。对吗? - Thomas Levesque
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接