2010-03-05 24 views
2

Dans mon application WPF, je communique de manière asynchrone avec un serveur. Le rappel ne sera donc pas exécuté dans le thread d'interface utilisateur, et comme j'ai besoin de faire quelque chose de WPF (créer un objet InkPresenter), j'ai besoin qu'il soit exécuté sur le thread de l'interface utilisateur. Eh bien, en fait, l'exigence est qu'il est exécuté sur un thread avec le mode STA appartement. J'ai essayé de créer un nouveau thread avec le mode STA, mais le résultat était que le thread d'interface utilisateur ne pouvait pas accéder à l'InkPresenter car il était "Possédé par un thread différent". Ce que je veux faire dans le rappel est d'utiliser le Dispatcher pour appeler ma fonction qui nécessite STA. Est-ce que cela ressemble à la bonne approche? Je fais ça maintenant, mais ça échoue toujours. Dans ma fonction de rappel, je déclenche la fonction suivante, qui essaie maintenant de s'assurer que la fonction adressée est exécutée sur le thread UI.L'utilisation du thread d'interface utilisateur WPF devrait toujours assurer le mode STA apartment, n'est-ce pas?

private void UpdateAnnotationsForCurrentFrameCollection() 
{ 
    if (Dispatcher.CurrentDispatcher.CheckAccess()) 
    { 
     DoSomethingIncludingInkPresenter(); 
    } 
    else 
    { 
     Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, 
      new Action(DoSomethingIncludingInkPresenter)); 
    } 
} 

private void DoSomethingIncludingInkPresenter() 
{ 
    var inkPresenter = XamlReader.Parse(_someXamlString) as InkPresenter; 
    // Do something with the inkPresenter.. 
} 

Comme vous le voyez de l'échantillon que j'utiliser CheckAccess() pour veiller à ce que je n'invoquons la fonction si elle est pas déjà exécuté sur le thread d'interface utilisateur. Lorsque mon rappel appelle cette fonction CheckAccess() est toujours vrai, mais Dispatcher.CurrentDispatcher.Thread.ApartmentState est MTA. Pourquoi? J'ai essayé de supprimer CheckAccess() et de toujours faire Invoke, mais l'ApartmentState reste MTA et la création de InkPresenter échoue.

Quelqu'un peut-il s'il vous plaît m'expliquer ce que je fais mal ici? Est-ce que j'ai le mauvais Dispatcher ou quelque chose? Est-ce la bonne approche pour s'assurer que quelque chose est exécuté sur le thread de l'interface utilisateur?

Répondre

3

Je pense que vous confondez 2 exigences. WinForms et les threads principaux WPF sont marqués STA pour activer les appels COM (et ils pourraient se produire dans les contrôles).

Votre problème semble être le problème classique "l'interface utilisateur n'est pas thread-safe", et devrait être résolu en envoyant les pièces qui touchent l'interface utilisateur.

Mais vous ne devriez pas appeler CheckAccess sur la CurrentDispatche mais sur votre cible:
someControl.Dispatcher.CheckAccess

+0

Merci! Ehr .. Puis-je vous déranger pour élaborer? :-) – stiank81

+0

J'étais encore en train d'éditer, mauvais répartiteur pour CheckAccess –

+0

Merci. Ceci est cependant dans un ViewModel, donc il n'y a pas de contrôles pour sortir le répartiteur. N'y a-t-il pas de «répartiteur général pour le fil de l'interface utilisateur»? Peut-être la réponse est que je ne devrais jamais mettre des objets WPF comme InkPresenter dans le ViewModel ..? Mais puis-je? Et si oui, comment puis-je obtenir le bon Dispatcher? – stiank81

2

Je pense que le problème est que vous utilisez le mauvais Dispatcher. Une des méthodes éprouvée que j'ai utilisée est de passer le Dispatcher du contrôle dans lequel le code s'exécute.

private void SomeMethod(Dispatcher dispatcher) 
{ 
    DoOtherThingsThatCanDoMTA(); 

    dispatcher.Invoke(new Action(()=> 
    { 
    DoSomethingThatRequiresSTA(); 
    })); 
} 

S'il n'est pas possible de transmettre le Dispatcher, vous pouvez l'exposer à une propriété ou à d'autres méthodes. J'espère que ça aide.

+0

Merci. Cela fonctionnerait probablement souvent, mais il ne semble pas que j'aie accès au bon Dispatcher. Je vais essayer une approche différente, mais j'apprécie votre contribution à ce sujet. – stiank81

+0

Ce n'est pas un problème MTA/STA. –