在Windows应用商店应用中获取CoreDispatcher的正确方法


83

我正在构建Windows应用商店应用,并且我有一些代码需要发布到UI线程中。

为此,我想检索CoreDispatcher并使用它发布代码。

看来有几种方法可以这样做:

// First way
Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.Dispatcher;

// Second way
Window.Current.Dispatcher;

我不知道哪一个是正确的?还是两者相等?


3
两者都是样的正确的,但它会为空,如果你不从一些已经访问它具有访问调度。如果要在ViewModel或Controller中使用它,则需要存储Dispatcher(通常作为App.xaml.cs或IOC控制器中的静态属性),并从第一页进行设置。你有负担。
Nate Diamond

Answers:


148

这是首选方式:

Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
    // Your UI update code goes here!
});

这样做的好处是它成为主体CoreApplicationView,因此始终可用。更多细节在这里

您可以使用两种替代方法。

第一种选择

Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().CoreWindow.Dispatcher

这将获取该应用程序的活动视图,但是如果未激活任何视图,它将为您提供null。更多细节在这里

第二选择

Window.Current.Dispatcher

从另一个线程调用此解决方案将不起作用,因为它返回null而不是UI Dispatcher。更多细节在这里


我尝试了此操作,但是当我跟踪代码时,委托代码仍在Worker线程而非“ Main Thread”上执行。
罗伯特·奥斯赫勒

3
请注意,(至少在Windows 8.1中)DispatcherPriority现在是CoreDispatcherPriority
Illidan

2
只要我们具有单个ASTA(应用程序单线程单元),这将起作用。如果我们引入“共享目标”功能,则有多个ASTA(每个ASTA都有自己的调度程序)。然后,CoreApplication.MainView可以为null(因为尚未初始化其ASTA)。意识到!
Yury Schkatula '17

我已经看到CoreApplication.MainView从非UI线程调用时导致程序挂起。我必须在启动时隐藏CoreApplication.MainView.CoreWindow.Dispatcher以便以后访问。
sjb-sjb

15

对于使用C ++ / CX的任何人

Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
    CoreDispatcherPriority::Normal,
    ref new Windows::UI::Core::DispatchedHandler([this]()
{
    // do stuff
}));

1
“要使用C ++创作和使用Windows运行时API,请使用C ++ / WinRT。这是Microsoft建议的Windows Runtime C ++模板库(WRL)和C ++ / CX的替代品。” C ++ / WinRT
Richard Chambers

2
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
            CoreDispatcherPriority.Normal,
            () => { // your code should be here});

1

虽然这是一个老话题,但我想提请注意开发人员可能遇到的可能影响我的问题,这使得在大型UWP应用程序中调试非常困难。就我而言,我在2014年根据上述建议重构了以下代码,但偶尔会因偶尔出现的应用程序冻结而受到困扰,这些冻结本质上是随机的。

public static class DispatcherHelper
{
    public static Task RunOnUIThreadAsync(Action action)
    {
        return RunOnUIThreadAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, action);
    }

    public static async Task RunOnUIThreadAsync(Windows.UI.Core.CoreDispatcherPriority priority, Action action)
    {
        try
        {
            await returnDispatcher().RunAsync(priority, () =>
            {
                action();
            });
        }
        catch (Exception ex)
        {
            var noawait = ExceptionHandler.HandleException(ex, false);
        }
    }

    private static Windows.UI.Core.CoreDispatcher returnDispatcher()
    {
        return (Windows.UI.Xaml.Window.Current == null) ?
            CoreApplication.MainView.CoreWindow.Dispatcher :
            CoreApplication.GetCurrentView().CoreWindow.Dispatcher;
    }
}

从上面开始,我使用了一个静态类来允许在整个应用程序中调用Dispatcher-允许单个调用。在95%的时间内,即使通过质量检查回归,一切都很好,但是客户会不时报告问题。解决的办法是将下面的调用包括在内,而不是在实际页面中使用静态调用。

            await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            { 

            });

当我需要确保从App.xaml.cs或处理推入/弹出到堆栈的Singleton NavigationService调用UI线程时,情况并非如此。当堆栈具有从MessageBus触发的各种消息时,由于每个页面都有其自己的UI线程,因此调度程序显然无法跟踪调用了哪个UI Thread。

希望这对可能受到影响的其他人有所帮助,也是我认为每个平台都可以通过发布涵盖最佳实践的完整项目来为开发人员提供服务的地方。


0

实际上,我会提出以下建议:

return (Window.Current == null) ? 
    CoreApplication.MainView.CoreWindow.Dispatcher : 
    CoreApplication.GetCurrentView().CoreWindow.Dispatcher

这样,如果您要开放另一个视图/窗口,就不会使Dispatchers感到困惑...

这个小宝石检查是否甚至还有一个窗口。如果不存在,请使用MainView的Dispatcher。如果有视图,请使用该人的分派器。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.