Правильный способ получить CoreDispatcher в приложении Windows Store

83

Я создаю приложение Windows Store, и у меня есть код, который нужно опубликовать в потоке пользовательского интерфейса.

Для этого я хотел бы получить CoreDispatcher и использовать его для публикации кода.

Похоже, есть несколько способов сделать это:

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

// Second way
Window.Current.Dispatcher;

Интересно, какой из них правильный? или если оба эквивалентны?

лизергиновая кислота
источник
3
Оба вида правильные, но она будет аннулирована , если вы не доступ к нему с чем - то , что уже имеет доступ к диспетчеру. Если вы хотите использовать его, скажем, в ViewModel или контроллере, вам необходимо сохранить Dispatcher, как правило, как статическое свойство в вашем контроллере App.xaml.cs или IOC, и установить его с первой страницы, которая у вас есть груз.
Нейт Даймонд

Ответы:

149

Это предпочтительный способ:

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 . Подробнее здесь .

MAXE
источник
Я пробовал это, но когда я отслеживаю код, код делегата все еще выполняется в рабочем потоке, а не в «основном потоке».
Роберт Ошлер
3
Пожалуйста , обратите внимание , что (по крайней мере , в ОС Windows 8.1) DispatcherPriority теперь CoreDispatcherPriority
Иллидан
2
Это будет работать, пока у нас есть один ASTA (однопоточная квартира приложения). В случае, если мы вводим функцию «совместного использования цели», существует несколько ASTA (каждый со своим собственным диспетчером). И тогда CoreApplication.MainView может иметь значение null (поскольку его ASTA еще не инициализировано). Будьте внимательны!
Юрий Щкатула
Я видел, как CoreApplication.MainView приводил к зависанию моей программы при вызове из потока, отличного от пользовательского интерфейса. Мне пришлось спрятать CoreApplication.MainView.CoreWindow.Dispatcher при запуске, чтобы получить к нему доступ позже.
sjb-sjb 07
15

Для всех, кто использует C ++ / CX

Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(
    CoreDispatcherPriority::Normal,
    ref new Windows::UI::Core::DispatchedHandler([this]()
{
    // do stuff
}));
Бретт Пеннингс
источник
1
«Для создания и использования API среды выполнения Windows с использованием C ++ существует C ++ / WinRT. Это рекомендованная Microsoft замена библиотеке шаблонов C ++ среды выполнения Windows (WRL) и C ++ / CX». C ++ / WinRT
Ричард Чемберс
2
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
            CoreDispatcherPriority.Normal,
            () => { // your code should be here});
apramc
источник
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, который обрабатывал нажатие / всплытие в стек. Диспетчер явно не отслеживал, какой поток пользовательского интерфейса был вызван, поскольку каждая страница имеет свой собственный поток пользовательского интерфейса, когда в стеке было множество сообщений, запускаемых из MessageBus.

Надеюсь, это поможет другим, которые могут быть затронуты, и я думаю, что именно здесь каждая платформа окажет услугу своим разработчикам, опубликовав полный проект, охватывающий лучшие практики.

Дэйв Фридель
источник
0

Собственно, я бы предложил что-то вроде этого:

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

Таким образом, если вы откроете еще один вид / окно, вы не запутаете диспетчеров ...

Эта маленькая жемчужина проверяет, есть ли вообще Окно. Если нет, используйте диспетчер MainView. Если есть представление, используйте его Диспетчер.

JH
источник