WindowsストアアプリでCoreDispatcherを取得する正しい方法


83

Windowsストアアプリを構築していますが、UIスレッドに投稿する必要のあるコードがいくつかあります。

そのために、CoreDispatcherを取得し、それを使用してコードを投稿したいと思います。

これを行うにはいくつかの方法があるようです。

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

// Second way
Window.Current.Dispatcher;

どちらが正しいのだろうか?または両方が同等である場合?


3
どちらも、ある種類正しいのが、あなたはすでに何かからそれをアクセスしていない場合にはnullになります持っているディスパッチャへのアクセスを。たとえば、ViewModelまたはControllerで使用する場合は、Dispatcherを、通常はApp.xaml.csまたはIOCコントローラーの静的プロパティとして保存し、最初のページから設定する必要があります。負荷があります。
ネイトダイヤモンド

回答:


148

これが推奨される方法です。

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

これが持つ利点は、メインCoreApplicationViewを取得するため、いつでも利用できることです。詳細はこちら

使用できる2つの選択肢があります。

最初の選択肢

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

これにより、アプリのアクティブなビューが取得されますが、ビューがアクティブ化されていない場合はnullになります。詳細はこちら

2番目の選択肢

Window.Current.Dispatcher

このソリューションは、UIディスパッチャーの代わりにnullを返すため、別のスレッドから呼び出された場合は機能しません。詳細はこちら


これを試しましたが、コードをトレースすると、デリゲートコードは「メインスレッド」ではなくワーカースレッドで実行されています。
ロバートオシュラー2014

3
(少なくともWindows 8.1では)DispatcherPriorityがCoreDispatcherPriorityになっていることに注意してください
Illidan

2
これは、単一のASTA(アプリケーションシングルスレッドアパートメント)がある限り機能します。「ターゲットの共有」機能を導入する場合、複数のASTAがあります(それぞれに独自のディスパッチャーがあります)。そして、CoreApplication.MainViewをnullにすることができます(そのASTAがまだ初期化されていないため)。注意してください!
Yury Schkatula 2017年

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があります。これは、WindowsランタイムC ++テンプレートライブラリ(WRL)およびC ++ / CXの代わりにMicrosoftが推奨するものです。」C ++ / WinRT
リチャードチェンバーズ

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を呼び出すことができ、1回の呼び出しが可能でした。95%の時間、QA回帰を行ってもすべてが正常でしたが、クライアントは時々問題を報告していました。解決策は、実際のページで静的呼び出しを使用せずに、以下の呼び出しを含めることでした。

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

            });

これは、UIスレッドがApp.xaml.csまたはスタックへのプッシュ/ポップを処理するシングルトンNavigationServiceから呼び出されたことを確認する必要がある場合には当てはまりません。スタックにMessageBusからトリガーされるさまざまなメッセージがある場合、各ページには独自のUIスレッドがあるため、ディスパッチャはどのUIスレッドが呼び出されたかを追跡できなくなっていたようです。

これが影響を受ける可能性のある他の人に役立つことを願っています。また、ベストプラクティスをカバーする完全なプロジェクトを公開することで、各プラットフォームが開発者にサービスを提供すると思います。


0

実際、私はこれに沿って何かを提案します:

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

そうすれば、別のビュー/ウィンドウをオープンエンドにした場合でも、ディスパッチャが混乱することはありません...

この小さな宝石は、窓さえあるかどうかをチェックします。ない場合は、MainViewのディスパッチャーを使用します。ビューがある場合は、そのディスパッチャを使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.