2010-11-22 4 views
4

Ok, mon code actuel est en cours et probablement je vais essayer de faire la même chose avec le CTP Async. Mais je vais toujours aimer comprendre ce qui se passe.Le thread appelant ne peut pas accéder à cet objet car un thread différent le possède

J'ai une fonction comme ci-dessous

// In MainWindow.xaml.cs 
Task.Factory.StartNew(() => helper.Send()); 

// In class HttpHelper 
public void Send() 
{ 
    // ... 

    try 
    { 
     Status = Statuses.Uploading; 
     // write to request stream 

     Status = Statuses.Downloading; 
     // write to response stream 

     Status = Statuses.Idle; // the exception is thrown here 
     // ... 
    } 
    catch (Exception e) 
    { 
     // ... 
    } 
} 

complet Code pour HttpHelper@pastebin. Send() sur la ligne 76

Je me demande pourquoi je reçois l'exception? Peut-être que j'ai fait quelque chose de mal avec le threading, mais pourquoi l'exception est-elle levée seulement après avoir réussi à définir la propriété Status 2 fois?

MISE À JOUR: La cause ...

J'ai eu un gestionnaire d'événements, écoutant l'événement StatusChanged, en 1 si l'article, j'ai oublié d'utiliser le thread d'interface utilisateur de mettre à jour l'interface utilisateur

helper.StatusChanged += (s, evt) => 
{ 
    _dispatcher.Invoke(new Action(() => txtStatus.Text = helper.Status.ToString())); // I used _dispatcher here correctly 

    if (helper.Status == HttpHelper.Statuses.Idle || helper.Status == HttpHelper.Statuses.Error) 
     progBar.IsIndeterminate = false; // but not here 
}; 
+0

parce que parfois vous obtenez le thread de l'interface utilisateur et parfois vous ne le faites pas .... –

Répondre

3

Mise à jour: J'ai manqué le (dans ma défense, petit) commentaire dans votre code qui a donné que vous utilisez WPF/Silverlight et non Windows Forms.

Pourtant, on dirait que vous étiez en mesure de prendre l'essentiel de base de ce que je disais et l'appliquer à votre propre scénario correctement (en utilisant Dispatcher.Invoke plutôt que Control.Invoke) -Bien fait;)


Je suis deviner qu'un gestionnaire d'événements associé à votre événement StatusChanged met à jour un contrôle StatusLabel sur votre interface utilisateur? Si c'est le cas, alors vous devez Invoke appeler à partir du thread UI; .: par exemple

void HttpHelper_StatusChanged(object sender, EventArgs e) 
{ 
    var httpHelper = (HttpHelper)sender; 
    UpdateStatus(httpHelper.Status); 
} 

void UpdateStatus(HttpHelper.Statuses status) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new Action<HttpHelper.Statuses>(UpdateStatus), status); 
    } 
    else 
    { 
     // Your code probably doesn't look like this; 
     // it's just an example. 
     statusLabel.Text = status.ToString(); 
    } 
} 

La raison pour laquelle vous pouvez voir deux succès suivi d'un échec est un peu au-delà de moi; mais je sais que le contrôle StatusLabel en particulier peut être un peu évasive quand il s'agit de problèmes de threading. J'ai vu le code où il est mis à jour directement à partir des threads d'arrière-plan (généralement en raison de l'inconscience du développeur) sans exception; il me semble que tu as juste eu de la chance deux fois et malchanceux une fois.

+1

Virtual -1. NON!! C'est Dispatcher.Invoke(). C'est WPF/SilverLight pas WPF. – Aliostad

+0

@Aliostad: Bon appel; Je pense que je vois le problème, dans ce cas. Je vais mettre à jour (encore) ... –

+0

@Aliostad: Euh ... l'OP était assez intelligent pour le comprendre. Cela rend ma vie plus facile;) –

-1

Si Status est une variable globale, vous obtiendrez cette exception car plusieurs threads y accèdent et la mettent à jour en même temps. je suggère d'utiliser un verrou autour de lui

0

Est-ce que Status touche l'interface utilisateur? Parce que cela semble être ça.

Je ne peux que deviner mais j'imagine Status change quelque chose sur l'interface utilisateur qui doit être fait par Dispatcher.Invoke().

Questions connexes