2010-10-29 7 views
4

En application WPF J'utilise la zone de texte avec un style personnalisé dans lequel ContextMenu est outrepassée comme ceci:TextBox coutume ContextMenu dans le style, l'erreur de multithreading

<Style TargetType="{x:Type TextBox}"> 
    <Setter Property="ContextMenu"> 
     <ContextMenu> 
     <MenuItem Header="Copy"/> 
     </ContextMenu> 
    </Setter> 
    </Style> 

Cela fonctionne parfaitement jusqu'à ce que je courrai fenêtre avec TextBox dans différents sujets tels que ceci:

Thread thread = new Thread(()=> 
           { 
           TestWindow wnd = new TestWindow(); 
           wnd.ShowDialog(); 
           }); 
thread.SetApartmentState(ApartmentState.STA); 
thread.IsBackground = true; 
thread.Start(); 

Mais cela provoque InvalidOperationException « Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread est propriétaire. ».

Comment éviter ce problème?

Répondre

4

Le problème est que votre style est réutilisé en tant qu'optimisation, donc le ContextMenu est réutilisé - c'est standard et fonctionne bien pour un seul thread, mais pas pour multithread.

Je voudrais essayer de déplacer le style à la ResourceDictionary et le référencement comme un StaticResource, je marquerait alors avec: x: Shared = « false » Cela va créer une nouvelle instance à chaque fois que la ressource est accessible - Je ne suis pas Assurez-vous que cela fonctionne pour la touche "attraper tous" moins de style que vous avez. Ensuite, vous pourriez faire du menu contextuel une ressource et l'affiner comme une StaticResource - cela devrait le faire.

+0

Une autre solution consiste à utiliser un sélecteur d'événements pour rightclick et créer un ContextMenu à la volée. –

0

Dans votre morceau de code, vous voulez modifier l'interface utilisateur dans un thread non-UI, ce qui n'est pas autorisé.

Vous devez vous assurer que vous êtes sur le thread d'interface utilisateur lors de l'application des mises à jour de l'interface utilisateur. Vous pouvez vérifier si cela est nécessaire en vérifiant la valeur de object.InvokeRequired. Si nécessaire, vous pouvez appeler la méthode en appelant le object.Invoke([delegate]). En plus de cela, vous pouvez également utiliser le répartiteur, voir MSDN et this blog. Bonne lecture