Вопрос по multithreading, windows-runtime, .net – Выполнить код в потоке пользовательского интерфейса в WinRT

64

Как запустить код в потоке пользовательского интерфейса в WinRT (Windows 8 Metro)?

Invoke Метод не существует.

Примечание для будущих читателей: помните, что если ваше приложение имеет несколько окон - существует несколько потоков пользовательского интерфейса и диспетчеров. Filip Skakun

Ваш Ответ

6   ответов
0

элемента управления CaptureElement (который определен в XAML), он жаловался на то, что он подготовлен в другом потоке, хотя я пытался установить его из кода, который вызывался через Page_Loaded обработчик события. Я закончил тем, что использовал это, чтобы обойти это:

previewControl.Dispatcher.TryRunAsync(CoreDispatcherPriority.Normal, () => {
   previewControl.Source = _mediaCapture;
}).GetAwaiter().GetResult();
5

Получите TaskScheduler, связанный с пользовательским интерфейсом.

    var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();

Затем запустите новую задачу и на вышеупомянутом UISyncContext.

    Task.Factory.StartNew(() => { /* Do your UI stuff here; */}, new System.Threading.CancellationToken(), TaskCreationOptions.PreferFairness, UISyncContext);
Я также получаю InvalidOperation
К вашему сведению: я получаю InvalidOperationException & quot; Текущий SynchronizationContext не может использоваться в качестве TaskScheduler & quot ;.
Ваш SynchronizationContext является нулевым. Вот почему вы получаете это исключение. Ничего плохого в моем коде.
77

CoreWindow из не-пользовательского интерфейса потока. Следующий код будет работать везде, даже когдаGetForCurrentThread() или жеWindow.Current возвращаетсяnull.

CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
    <lambda for your code which should run on the UI thread>);

например:

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

Вам понадобится ссылкаWindows.ApplicationModel.Core Пространство имен:

using Windows.ApplicationModel.Core;
Я получаю это исключение, когда пытаюсь получить доступ к Диспетчеру. Я не выполнил какой-либо код с помощью диспетчера.
Я получаю System.NotImplementedException при использовании этого. Я обращаюсь к нему из потока пользовательского интерфейса.
ТакCoreApplication.MainView.CoreWindow.Dispatcher у вас не работает? Есть ли у вас исключение, когда вы пробуете другие решения?Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher? this.Dispatcher?
@ C & # x153; ты человек! ты мой герой
Здесь никогда не было этого исключения. Это может быть откуда-то еще, например, внутри инструкции вашего блока.
8

this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => Frame.Navigate(typeof(Welcome), this));

Меня устраивает.

На самом деле это не гарантирует запуск его в потоке пользовательского интерфейса. Это будет только в том случае, если & quot; это & quot; это объект в контексте пользовательского интерфейса.
0

DispatcherTimer тоже вариант.

Я использовал его для кода, который должен быть запущен в Xaml-конструкторе (CoreWindow.Dispatcher, ... недоступен в UWP-конструкторе)

var localTimer = new DispatcherTimer
{
    Interval = TimeSpan.FromMilliseconds(0)
};
localTimer.Tick += (timer, e) =>
{
    (timer as DispatcherTimer).Stop();
    action();
};
localTimer.Start();

Отказ от ответственности:
Я должен отметить, что это должно быть последним вариантом, если любой другой сбой.

69

Из вашего потока пользовательского интерфейса выполните:

var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;

Из вашего фона (не пользовательский интерфейс)

dispatcher.RunAsync(DispatcherPriority.Normal, 
    <lambda for your code which should run on the UI thread>);

Это должно работать как на CP, так и на более поздних сборках.

Итак, какие части моего приложения на самом деле работают в потоке пользовательского интерфейса? Я использую FrameWorkView (Windows :: ApplicationModel :: Core :: IFrameworkView) и не могу использовать диспетчер, полученный из метода Run (). Я получаю WrongThreadException, когда пытаюсь создать MediaElement с помощью RunAsync.
Есть ли способ получить диспетчер в потоке, не являющемся пользовательским интерфейсом? В настоящее время я получаю нулевое значение от CoreWindow.GetForCurrentThread ()
Нет. Диспетчеры связаны с потоком пользовательского интерфейса, поэтому вам необходимо получить диспетчер в потоке пользовательского интерфейса. Как только диспетчер найден, вы можете запомнить его. Если вы находитесь в приложении XAML, то большинство объектов пользовательского интерфейса имеют элемент диспетчера, который вы можете использовать.
@Larry: Вы можете получить Dispatcher из фоновой ветки, смотрите здесь:stackoverflow.com/a/25760799/543303 CoreApplication.MainView.CoreWindow.Dispatcher
Ваш исходный код выполняется в потоке пользовательского интерфейса, как и любые обратные вызовы событий на основе XAML). Если вы используете & quot; await & quot; Ключевое слово из потока пользовательского интерфейса, весь код после & quot; await & quot; Ключевое слово будет работать в потоке пользовательского интерфейса. Однако обратные вызовы событий от других API WinRT могут отсутствовать в потоке пользовательского интерфейса, в противном случае вы используете диспетчер для возврата в поток пользовательского интерфейса. Если вы получаете WrongThreadException, это, вероятно, означает, что WinRT API вошел в поток без пользовательского интерфейса.

Похожие вопросы