【问题标题】:Correct way to get the CoreDispatcher in a Windows Store app在 Windows 应用商店应用程序中获取 CoreDispatcher 的正确方法
【发布时间】:2013-05-10 07:24:15
【问题描述】:

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

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

似乎有几种方法可以做到:

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

// Second way
Window.Current.Dispatcher;

我想知道哪个是正确的?或者如果两者是等价的?

【问题讨论】:

  • 两者都是正确的种类,但如果您不是从已经具有对 Dispatcher 的访问权限的对象访问它,则它将为空。如果你想在 ViewModel 或 Controller 中使用它,那么你需要将 Dispatcher 存储为 App.xaml.cs 或 IOC 控制器中的静态属性,并从第一页设置它你有负载。

标签: c# windows-runtime windows-store-apps async-await dispatcher


【解决方案1】:

这是首选方式:

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

这样做的好处是它获得了主要的CoreApplicationView,因此始终可用。更多详情here.

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

第一选择

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

这将获取应用程序的活动视图,但如果没有激活任何视图,这将为您提供 null。更多详情here.

第二种选择

Window.Current.Dispatcher

当从另一个线程调用此解决方案时将不起作用,因为它返回 null 而不是 UI Dispatcher。更多详情here.

【讨论】:

  • 我试过了,但是当我跟踪代码时,委托代码仍在工作线程而不是“主线程”上执行。
  • 请注意(至少在 Windows 8.1 中)DispatcherPriority 现在是 CoreDispatcherPriority
  • 只要我们有单个 ASTA(应用程序单线程单元),它就可以工作。如果我们引入“共享目标”功能,则有多个 ASTA(每个都有自己的调度程序)。然后 CoreApplication.MainView 可以为空(因为它的 ASTA 尚未初始化)。请注意!
  • 我看到 CoreApplication.MainView 在从非 UI 线程调用时导致我的程序挂起。我必须在启动时隐藏 CoreApplication.MainView.CoreWindow.Dispatcher 以便以后访问它。
  • @GregoryBologna 很有趣...但我认为您的只是语法问题...任何 Lamba 表达式都可以以 {} 形式使用:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
【解决方案2】:

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

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

【讨论】:

  • “对于使用 C++ 创作和使用 Windows 运行时 API,有 C++/WinRT。这是 Microsoft 推荐的 Windows 运行时 C++ 模板库 (WRL) 和 C++/CX 的替代品。” C++/WinRT
【解决方案3】:
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
            CoreDispatcherPriority.Normal,
            () => { // your code should be here});

【讨论】:

    【解决方案4】:

    虽然这是一个旧线程,但我想提请注意开发人员可能遇到的一个可能的问题,该问题影响了我并使得在大型 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% 的时间里,即使通过 QA 回归,一切都很好,但客户会时不时地报告问题。解决方案是在下面包含调用,而不是在实际页面中使用静态调用。

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

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

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

    【讨论】:

      【解决方案5】:

      实际上,我会提出这样的建议:

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

      这样,如果您打开另一个视图/窗口,您就不会让调度程序感到困惑...

      这个小宝石会检查是否有窗口。如果没有,请使用 MainView 的 Dispatcher。如果有视图,请使用该视图的 Dispatcher。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-22
        • 1970-01-01
        • 2013-01-20
        相关资源
        最近更新 更多