web-dev-qa-db-fra.com

Le thread appelant ne peut pas accéder à cet objet car un autre thread le possède.WPF

A chaque fois que j'actualisais une étiquette, j'obtenais cette erreur:Le thread appelant ne peut pas accéder à cet objet car un autre thread le possède.J'ai essayé d'invoquer mais cela a échoué. J'utilise le formulaire WPF.

delegate void lostfocs(string st);
   private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {

        Thread t = new Thread(modi);
        t.Start();
    }
 void modi()
    {
        try
        {
            label1.Content = "df";
        }
        catch
        {
            lostfocs ld = new lostfocs(up);
          //  ld.Invoke("df");
            object obj=new object();
            ld.Invoke("sdaf");
        }
    }
void up(string st)
    {
        label1.Content = st;
    }
22
Yasser

Utilisez Dispatcher.Invoke Method. 

Exécute le délégué spécifié de manière synchrone sur le thread le Dispatcher est associé à.

Également

Dans WPF, seul le thread ayant créé un DispatcherObject peut accéder à cet objet. Par exemple, un thread d'arrière-plan qui est dérivé de le fil principal de l'interface utilisateur ne peut pas mettre à jour le contenu d'un bouton qui était créé sur le fil de l'interface utilisateur. Pour que le fil de fond soit accéder à la propriété Content du bouton, le thread d'arrière-plan doit déléguer le travail à Dispatcher associé au thread d'interface utilisateur . Ceci est accompli en utilisant Invoke ou BeginInvoke. Invoke est synchrone et BeginInvoke est asynchrone. L'opération est ajoutée à la file d'événements de Dispatcher à la DispatcherPriority spécifiée.

Vous recevez l'erreur car votre étiquette est créée sur un thread d'interface utilisateur et que vous essayez de modifier son contenu via un autre thread. C'est là que vous auriez besoin de Dispatcher.Invoke. 

Consultez cet article Les threads WPF créent des applications plus réactives avec le répartiteur

40
Habib

Vous pouvez utiliser Dispatcher pour cela. Votre code devient ...

private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
    {
        try
        {
            label1.Content = "df";
        }
        catch
        {
            lostfocs ld = new lostfocs(up);
          //  ld.Invoke("df");
            object obj=new object();
            ld.Invoke("sdaf");
        }
    }
));
17
gaurawerma

utiliser Dispatcher.Invoke

Exemple

    void modi()
    {
        if(!Dispatcher.CheckAccess())
        {
            Dispatcher.Invoke(
                    ()=>label1.Content = "df",DispatcherPriority.Normal);
        }
        else
        {
            label1.Content = "df";
        }
    }
11
Tilak

J'ai commencé un thread non-UI et dans ce fil, j'ai également regardé un thread UI. Donc, mon exigence est comme exécuter un thread d'interface utilisateur dans un thread non-interface utilisateur. Lors de la gestion de ce scénario, l'exception suivante a été générée . "Exception: le thread appelant ne peut pas accéder à cet objet car un autre thread le possède."

Dans ce cas, j'ai utilisé la méthode Dispatcher.Invoke de l'élément d'interface utilisateur comme suit et cela a bien fonctionné.

if (m_contextWindow == null)
{   
    System.Threading.Thread newWindowThread = new System.Threading.Thread(new ThreadStart( () =>
    {
        // Create and show the Window
        m_contextWindow = new ContextWindow();
        m_contextWindow.DataContext = this;                            
        m_contextWindow.Show();
        // Start the Dispatcher Processing
        System.Windows.Threading.Dispatcher.Run();
    }));

    // Set the apartment state
    newWindowThread.SetApartmentState(ApartmentState.STA);
    // Make the thread a background thread
    newWindowThread.IsBackground = true;
    // Start the thread
    newWindowThread.Start();
}
else
{                     
    this.m_contextWindow.Dispatcher.Invoke(new ThreadStart(() => 
    {
        m_contextWindow.DataContext = this;
        if (m_contextWindow.Visibility == System.Windows.Visibility.Collapsed
         || m_contextWindow.Visibility == System.Windows.Visibility.Hidden)
            m_contextWindow.Visibility = System.Windows.Visibility.Visible;
    }));                            
}
1
Srikanth Dornala

Plusieurs suggestions pour utiliser BeginInvoke, mais aucune mention de EndInvoke. La bonne pratique est que "chaque BeginInvoke a un EndInvoke correspondant" et qu'il doit y avoir une certaine protection contre les conditions de concurrence (pensez: que se passe-t-il avec plusieurs codes BeginInvoke mais qu'aucun n'a encore fini de traiter?)

C'est facile à oublier, et j'ai vu cette erreur (et oui, c'est c'est une erreur) dans les exemples MSDN et les livres publiés sur WinForms

0
brewmanz
private void imgPayment_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
            {
                try
                {
                    label1.Content = "df";
                }
                catch
                {
                    lostfocs ld = new lostfocs(up);
                    object obj = new object();
                    ld.Invoke("sdaf");
                }
            }));
        }
0
Kishore Kumar