2017-08-10 1 views
0

Dernière modification: Problème avéré sans rapport avec cette implémentation asynchrone. La première réponse m'a aidé à déplacer assez de choses pour regarder le problème avec une nouvelle paire d'yeux. Merci les gars.L'interface utilisateur ne répond pas en attente

Je parle avec une caméra IP dans mon application, à la fois via httpclient (pour demander et recevoir l'image) et une socket web (via websocket-sharp, pour recevoir des données).

En ce moment j'ouvre simplement la websocket et demande une image (les boucles viendront plus tard). Demander l'image est la dernière chose que je fais.

Lorsque je définis la demande de l'image comme

string picloc = "[redacted]"; 
Stream imgstream = await client.GetStreamAsync(picloc).ConfigureAwait(false); 
Bitmap blah2 = new Bitmap(imgstream); 
BMPReadyEventArgs args = new BMPReadyEventArgs(); 
args.BMP = blah2; 
BitmapReady(this, args); 

l'application traverse tout le code et se fige. Si je laisse le terme ConfigureAwait désactivé, l'attente abandonnera le contrôle au code de l'interface utilisateur, il atteindra la fin de ce code, gèlera pendant quelques secondes et chargera l'image. Avec configureawait (false), il chargera l'image, puis gèlera. Je pense que le flux que je reçois de la requête démarre immédiatement, donc s'il ne doit pas attendre le contexte (?), Il fonctionne essentiellement de manière synchrone. Pour être honnête, je ne comprends toujours pas vraiment ce que configureeawait fait réellement, ni ce que les gens parlent en réalité, mais ce comportement me fait penser que le gel de l'interface n'a rien à voir avec la nature asynchrone du code. Je ne peux pas voir le débogueur sauter à un endroit inattendu en passant par F11 (bien que cela semble avoir quelques lacunes lorsqu'il est utilisé avec du code asynchrone), il semble vraiment juste atteindre la fin du code et geler pendant quelques secondes.

Cela m'amène à quelques questions.

L'interface utilisateur se bloquera-t-elle toujours lorsque la fin du code est atteinte et, si oui, dois-je faire une sorte de ticker de rafraîchissement de l'interface utilisateur?

Et, encore, mais plus nébuleusement,

Y at-il un problème avec ma mise en œuvre async qui pourrait être la cause de ce gel?

Edit: Méthode complète:

public async void DownloadJPG() 
    { 
     string picloc = "[redacted]"; 
     Stream imgstream = await client.GetStreamAsync(picloc).ConfigureAwait(false); 
     Bitmap blah2 = new Bitmap(imgstream); 
     BMPReadyEventArgs args = new BMPReadyEventArgs(); 
     args.BMP = blah2; 
     BitmapReady(this, args); 
    } 

appelé à partir

private async void HoldingPattern() 
    { 
     textBox1.Text = wsmanager.passer; 
     connector.BitmapReady += (sender, e) => 
      pictureBox1.Image = e.BMP; 

     connector.DownloadJPG(); 
    } 

Edit2: gestionnaire d'événements:

public event EventHandler<BMPReadyEventArgs> BitmapReady; 

BMPReadyEventArgs

class BMPReadyEventArgs:EventArgs 
{ 
    public Bitmap BMP {get;set;} 
} 
+0

S'il vous plaît montrer la méthode complète et comment vous appelez ce –

+0

Je ne pense pas que vous avez montré assez de code pour quiconque d'aider.Par exemple, l'appel à 'BitmapReady' semble déclencher un événement, mais vous n'avez pas affiché le gestionnaire d'événements ou l'emplacement de ce gestionnaire d'événements. Si elle s'exécute sur le thread de l'interface utilisateur, cela peut-il être la cause de votre interface utilisateur de gel? Si oui, doit-il être asynchrone? –

+0

Mais où est le code qui s'exécute lorsque le gestionnaire 'BitmapReady' est levé (c'est-à-dire le code de l'abonné)? –

Répondre

0

Votre approche est une façon de compliquer

public async Task<Image> DownloadJPGAsync() 
{ 
    string picloc = "[redacted]"; 
    Stream imgstream = await client.GetStreamAsync(picloc).ConfigureAwait(false); 
    Bitmap blah2 = new Bitmap(imgstream); 
    return blah2; 
} 

Maintenant, à partir d'un gestionnaire d'événements async

public async void Button1_Click() 
{ 
    var image = await connector.DownloadJPGAsync(); 
    pictureBox1.Image = image; 
} 
+0

La tâche récupère l'image de la caméra et la convertit en bitmap, mais s'arrête avant de la renvoyer. Je ne suis pas sûr pourquoi il ne retourne pas le bitmap, mais je m'égare. Même si cela fonctionne, ce n'est pas comme ça que je veux structurer mon application, car je veux gérer la récupération des bitmaps séparément de l'interface utilisateur (je sais que je demande à mon gestionnaire de client web de la récupérer depuis l'interface utilisateur, mais changé sur la route). Même si je voulais l'appeler directement dans mon fil de l'interface utilisateur, comme je l'ai mentionné dans un commentaire sur mon message d'origine, attendre dans l'interface utilisateur n'est probablement pas le meilleur car il va geler l'interface utilisateur en attente. –

+0

Désolé, j'ai simplement oublié de remplacer [expurgé] par le chemin actuel. La tâche fonctionne, mais a le problème de geler le thread d'interface utilisateur. Il semble être dû à l'attente dans le fil de l'interface utilisateur maintenant, cependant, au lieu d'un inconnu. Je vais essayer de déplacer l'appel de tâche à l'endroit où il appartient et faire un rapport. –

+0

Le "attendre dans le fil de l'interface utilisateur" est là pour ** ne pas bloquer ** l'UIThread! Êtes-vous sûr d'avoir ConfigureAwait (false) après GetStreamAsync (...)? Sinon, la création de Bitmap se fera sur UIThread et la création prendra du temps –