67 votes

Exécuter du code sur le thread de l'interface utilisateur dans WinRT

Comment puis-je exécuter du code sur le thread de l'interface utilisateur dans WinRT (Windows 8 Metro) ?

Le site Invoke n'existe pas.

8 votes

Note aux futurs lecteurs : N'oubliez pas que si votre application comporte plusieurs fenêtres, il y a plusieurs threads et répartiteurs d'interface utilisateur.

80voto

Cœur Points 1538

Il est plus facile d'obtenir directement le CoreWindow à partir du thread non-UI. Le code suivant fonctionnera partout, même lorsque GetForCurrentThread() ou Window.Current renvoie à null .

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

par exemple :

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

Vous devrez faire référence Windows.ApplicationModel.Core espace de noms :

using Windows.ApplicationModel.Core;

0 votes

Je reçois une exception System.NotImplementedException lorsque j'utilise cette fonction, à laquelle j'accède depuis le fil d'exécution de l'interface utilisateur.

0 votes

Je n'ai jamais eu cette exception ici. Elle peut provenir d'un autre endroit, par exemple de vos instructions de bloc.

0 votes

J'ai obtenu cette exception lorsque j'ai essayé d'accéder au répartiteur. Je n'ai pas exécuté de code utilisant le répartiteur.

69voto

Larry Osterman Points 12713

Utilisez :

Depuis le fil d'exécution de l'interface utilisateur, exécutez :

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

Depuis votre arrière-plan (fil non UI)

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

Cela devrait fonctionner à la fois sur le CP et les constructions ultérieures.

5 votes

Existe-t-il un moyen d'obtenir un répartiteur sur un thread non-UI ? Actuellement, j'obtiens null de CoreWindow.GetForCurrentThread().

3 votes

Non. Les répartiteurs sont liés à un thread d'interface utilisateur, vous devez donc récupérer le répartiteur sur le thread d'interface utilisateur. Une fois que le répartiteur a été récupéré, vous pouvez vous en souvenir. Si vous êtes dans une application XAML, la plupart des objets de l'interface utilisateur ont un membre dispatcher que vous pouvez utiliser.

0 votes

Quelles sont donc les parties de mon application qui s'exécutent réellement dans le Thread UI ? J'utilise un FrameWorkView (Windows::ApplicationModel::Core::IFrameworkView), et je ne suis pas en mesure d'utiliser le dispatcher que j'ai acquis à partir de la méthode Run()-. Je reçois une WrongThreadException lorsque j'essaie de créer MediaElement par RunAsync.

8voto

Utilisez :

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

Ça marche pour moi.

5 votes

Cela ne garantit pas réellement l'exécution sur le thread de l'interface utilisateur. Elle ne le fera que si "this" est un objet dans le contexte de l'interface utilisateur.

5voto

Deeb Points 87

C'est un moyen beaucoup plus facile à mon avis.

Obtenez le TaskScheduler associé à l'interface utilisateur.

    var UISyncContext = TaskScheduler.FromCurrentSynchronizationContext();

Ensuite, lancez une nouvelle tâche et sur le UISyncContext ci-dessus.

    Task.Factory.StartNew(() => { /* Do your UI stuff here; */}, new System.Threading.CancellationToken(), TaskCreationOptions.PreferFairness, UISyncContext);

0 votes

Pour info : je reçois une InvalidOperationException "The current SynchronizationContext may not be used as a TaskScheduler".

0 votes

J'obtiens également un InvalidOperation

1 votes

Votre SynchronizationContext est nul. C'est pourquoi vous obtenez cette exception. Rien d'anormal dans mon code.

0voto

Warappa Points 2704

DispatcherTimer est également une option.

Je l'ai utilisé pour le code qui doit être exécuté dans Xaml-designer (CoreWindow.Dispatcher,... ne sont pas disponibles dans UWP-designer).

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

Avis de non-responsabilité :
Je tiens à préciser qu'il s'agit d'une option de dernier recours si toutes les autres échouent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X