Правильний спосіб отримати CoreDispatcher у програмі Windows Store


83

Я створюю додаток Windows Store і маю код, який потрібно розмістити в потоці інтерфейсу користувача.

Для цього я хотів би отримати CoreDispatcher і використовувати його для розміщення коду.

Здається, що це можна зробити декількома способами:

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

// Second way
Window.Current.Dispatcher;

Цікаво, який з них правильний? або якщо обидва еквівалентні?


3
Обидва види правильні, але вона буде анульована , якщо ви не доступ до нього з чим - то , що вже має доступ до диспетчера. Якщо ви хочете використовувати його, скажімо, у ViewModel або контролері, тоді вам потрібно буде зберегти диспетчер, як правило, як статичну властивість у вашому App.xaml.cs або контролері IOC, і встановити його з першої сторінки у вас є навантаження.
Nate Diamond

Відповіді:


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

Це отримує активний вигляд програми, але це дасть вам нуль , якщо жодного перегляду не було активовано. Детальніше тут .

Друга альтернатива

Window.Current.Dispatcher

Це рішення не буде працювати, коли його викликають з іншого потоку, оскільки воно повертає null замість UI Dispatcher . Детальніше тут .


Я спробував це, але коли я відстежую код, код делегата все ще виконується в потоці Worker, а не "Основній нитці".
Robert Oschler

3
Зверніть увагу, що (принаймні в Windows 8.1) DispatcherPriority тепер є CoreDispatcherPriority
Illidan,

2
Це буде працювати, поки у нас є одна ASTA (заявка однопоточна квартира). Якщо ми вводимо функцію "спільного використання цілей", існує кілька ASTA (кожна з яких має свого диспетчера). І тоді CoreApplication.MainView може бути нульовим (оскільки його ASTA ще не ініціалізовано). Бережись!
Yury Schkatula

Я бачив, як 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
"Для створення та споживання API середовища виконання Windows із використанням C ++ існує C ++ / WinRT. Це рекомендована корпорацією Майкрософт заміна бібліотеки шаблонів Windows Runtime C ++ (WRL) та C ++ / CX." 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;
    }
}

З вищевикладеного, я використовував статичний клас, щоб дозволити виклик диспетчера через програму - дозволяючи один виклик. Протягом 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. Якщо є погляд, скористайтеся цим диспетчером.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.