2017-05-04 3 views
0

J'ai une application Windows 10 UWP et dans mon XAML, j'ai un StackPanel qui est utilisé pour afficher une barre de progression. Par conséquent, la visibilité de StackPanel est définie par défaut sur réduit. Ensuite, dans mon code derrière, j'essaie de définir la visibilité visible lorsque l'utilisateur clique sur un bouton et après, j'appelle une méthode pour effectuer un traitement. Avec cet exemple, le panneau ne s'affiche jamais.Windows 10 UWP StackPanel La visibilité ne fonctionne pas

private void BtnProcess_OnClick(object sender, RoutedEventArgs e) 
    { 
     //Set the progress panel to visible 
     toggleProgressPanel(true); 
     //This is a long running process that can take 3-5 seconds. 
     ProcessRequest(); 
     //Hide the progress panel 
     toggleProgressPanel(false); 
    } 

    private void toggleProgressPanel(bool show) 
    { 
     pnlProgressBar.Visibility = show ? Visibility.Visible : Visibility.Collapsed; 
    } 

Une chose que je remarqué au cours des essais est que si je commente sur l'appel ProcessRequest et, évidemment, la dissimulation du panneau de progression, il se présentera à ce moment-là. J'ai également essayé d'afficher et de masquer le panneau à l'intérieur de l'appel de méthode ProcessRequest, en le montrant au tout début de la méthode et en le repliant à la toute fin.

J'ai vérifié que le processus de la méthode de longue durée prend en fait 3-5 secondes pour s'exécuter, donc ce n'est pas qu'il cache le panneau si vite que vous ne le voyez jamais.

Il semble presque que ce soit un problème d'actualisation de l'interface utilisateur, mais je ne suis pas sûr de savoir comment y remédier. Il semble que parce que la méthode appelante BtnProcess_OnClick est en train de tout faire, l'interface utilisateur ne s'actualise jamais tant que la méthode BtnProcess_OnClick n'est pas complète et retourne et c'est pourquoi elle n'apparaît jamais. Est-ce exact? Comment travaillez-vous autour de ceci si c'est le cas? Je suis réticent à mettre l'appel de méthode ProcessRequest à l'intérieur d'un Task.Run parce que cette méthode doit faire une bonne quantité d'interaction avec l'interface utilisateur et cette solution le mettrait sur un thread différent, ce qui signifie que je devrais écrire une bonne quantité de code (je pense) pour ensuite contourner cela. Il semble qu'il doit y avoir une solution facile qui me manque?

Merci!

+0

ProcessRequest() doit être une méthode asynchrone. – Archana

+0

@Archana Merci pour la réponse. Donc, si c'est asynchrone, je peux toujours accéder à toutes mes interfaces car je ne suis pas techniquement sur un autre thread, ce qui est bien. La raison pour laquelle je n'ai pas fait cela est parce que rien dans cette méthode n'est attendu. D'après ce que je comprends, même si je fais la méthode async, s'il n'y a rien d'attendu à l'intérieur de la méthode, elle fonctionnera quand même en synchronisation. Est-ce correct ou dois-je aussi ajouter un abritrary attendre Task.Delay (100); ou quelque chose comme ça pour forcer une attente? –

+0

Si cela prend 3-5 secondes, ce serait suffisant. Maintenant votre interface utilisateur de blocage pendant 3-4 secondes, donc tout changement que vous faites à la visibilité ne sera pas reflété. – Archana

Répondre

0

Par recommandation d'Archana, j'ai appelé ma méthode à ProcessRequest async. Cependant, je n'ai rien de ce qui est attendu à l'intérieur de cette méthode. Donc, le simple fait de marquer la signature de la méthode comme async sans waitable la fait fonctionner de façon synchrone (d'après ce que je comprends). Donc, pour le forcer à courir async, j'ai ajouté l'intérieur suivant de ma méthode, ainsi que le marquer Async:

await Task.Delay(50); 

Ceci est juste un petit retard qui est à peine perceptible, mais me donne aussi quelque chose qui est awaitable l'intérieur de la méthode.

Ensuite, j'ai également changé l'appelant de cette méthode, dans mon cas le bouton presse l'événement et l'a fait asynchrone aussi bien et l'a fait attendre l'appel à la méthode. Maintenant, cela fonctionne comme prévu et mon interface utilisateur est mise à jour à chaque fois. Voici le code complet:

private async void BtnProcess_OnClick(object sender, RoutedEventArgs e) 
{ 
    //Set the progress panel to visible 
    toggleProgressPanel(true); 
    //This is a long running process that can take 3-5 seconds. 
    await ProcessRequest(); 
    //Hide the progress panel 
    toggleProgressPanel(false); 
} 

private void toggleProgressPanel(bool show) 
{ 
    pnlProgressBar.Visibility = show ? Visibility.Visible : Visibility.Collapsed; 
} 

private async Task ProcessRequest() 
{ 
    await Task.Delay(50); 
    //Now do all of my long running code here 
} 

Faire tout cela permet un contrôle de revenir à l'appelant de ma méthode longue de la course, dans mon cas l'événement de presse de bouton, tandis que la longue méthode de fonctionnement de ProcessRequest continue async travailler. En renvoyant le contrôle à l'appelant, il peut terminer et autoriser l'interface utilisateur à mettre à jour.

Espérons que cela aide!

+0

Essayez de placer votre tâche à long terme dans un 'wait.Run (() => ProcessRequest())' plutôt que dans un délai codé en dur comme cela. –

+0

Merci pour les commentaires. Si vous regardez le dernier paragraphe sur mon OP, j'ai mentionné cela comme une option, mais que j'étais réticent à le faire parce que ma méthode ProcessRequest qui est appelée a une quantité de travail sur les contrôles de l'interface utilisateur et de l'interface utilisateur. Task.Run force la méthode à s'exécuter sur un autre thread de sorte que je devrais changer les choses de manière significative ou ajouter une bonne quantité de code dans la méthode pour synchroniser avec les répartiteurs chaque fois que je veux accéder à l'interface utilisateur. On dirait une douleur à moins que je manque quelque chose. –