Quelles solutions ai-je pour empêcher l'IU de geler pendant que je désérialise un grand nombre d'éléments d'interface utilisateur dans WPF? Je reçois des erreurs se plaignant que les objets appartiennent sur le Thread UI lorsque je suis en train de les charger dans un autre thread. Alors, quelles options ai-je pour empêcher l'erreur Vista "Ne répond pas au programme" pendant que je charge mes données d'interface utilisateur? Puis-je me fier à une solution à un seul thread ou est-ce que je manque quelque chose concernant peut-être plusieurs threads de l'interface utilisateur?Empêche le gel de l'interface utilisateur sans threads supplémentaires
Répondre
Si vous n'utilisez qu'un seul thread, l'interface utilisateur se bloquera pendant toute la durée du traitement.
Si vous utilisez un thread BackgroundWorker, vous aurez plus de contrôle sur ce qui se passe & quand.
Pour mettre à jour l'interface utilisateur, vous devez utiliser Dispatcher.Invoke
à partir de votre thread d'arrière-plan pour marshal l'appel à travers la limite de fil.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
Vous pouvez toujours faire votre traitement long dans un thread séparé, mais lorsque vous avez terminé devez synchroniser avec le thread d'interface utilisateur en appelant Dispatcher.BeginInvoke(your_UI_action_here)
Recommandations du blog OldNewThing.
Il est préférable que vous utilisiez la procédure filetée, que vous disposiez d'un thread graphique et que vous chargiez votre travail dans un autre thread qui, une fois terminé, renvoie le thread principal de l'interface graphique. La raison en est que vous n'entrerez pas dans les problèmes de thread avec votre interface graphique.
So Un fil GUI Nombreux threads de travail qui font le travail.
Si l'un de vos threads se bloque, l'utilisateur est en contrôle direct sur votre application peut fermer le thread sans affecter son expérience avec l'interface de l'application. Cela le rendra heureux parce que votre utilisateur se sentira dans le contrôle autre que lui cliquez constamment sur ce bouton d'arrêt et il ne va pas arrêter de chercher.
Essayez freezing vos UIElements. Les objets gelés peuvent être transmis entre les threads sans rencontrer d'exception InvalidOperationException, donc vous les désérialisez & les geler sur un thread d'arrière-plan avant de les utiliser sur votre thread d'interface utilisateur.
Vous pouvez également envisager de renvoyer les désérialisations individuelles vers le thread UI à la priorité d'arrière-plan. Ce n'est pas optimal, car le thread de l'interface utilisateur doit encore faire tout le travail pour désérialiser ces objets et il y a une surcharge ajoutée en les répartissant comme des tâches individuelles, mais au moins vous ne bloquerez pas l'interface utilisateur. sera en mesure d'être intercalé avec votre travail de désérialisation de moindre priorité.
Cela ne fonctionne que pour les freezables et les éléments de l'interface utilisateur ne sont pas freezable. Donc, si vous parlez de créer une géométrie, des pinceaux, etc., cela fonctionne, mais si vous parlez de construire des éléments d'interface utilisateur (c'est-à-dire la classe Visual et la chaîne d'héritage), ce n'est pas le cas. –
Oups, bon point sur UIElement n'étant pas gelable. –
Here is a wonderful blog posting from Dwane Need qui décrit toutes les options disponibles pour travailler avec des éléments d'interface utilisateur parmi plusieurs threads.
Vous n'avez vraiment pas donné assez de détails pour donner une bonne prescription. Par exemple, pourquoi créez-vous vous-même des éléments d'interface utilisateur au lieu d'utiliser la liaison de données? Vous pourriez avoir une bonne raison, mais sans plus de détails, il est difficile de donner de bons conseils. Comme autre exemple de détail utile, cherchez-vous à construire des hiérarchies de contrôle complexes et imbriquées pour chaque donnée ou avez-vous besoin de dessiner une forme simple?
Vous pouvez activer le flux de contrôle à l'aide de DispatcherFrames, ce qui permet de désérialiser le thread d'interface en arrière-plan.
D'abord vous avez besoin d'un moyen d'obtenir le contrôle périodiquement pendant la désérialisation. Quel que soit le désérialiseur que vous utilisez, il devra appeler des ensembles de propriétés sur vos objets, de sorte que vous pouvez généralement ajouter du code aux paramètres de propriété. Vous pouvez également modifier le désérialiseur. Dans tous les cas, assurez-vous que votre code est appelé assez souvent
Chaque fois que vous contrôlez recevez, tout ce que vous devez faire est:
- Créer un DispatcherFrame
- file d'attente d'un événement au répartiteur à l'aide BeginInvoke que jeux Continuer = false sur le cadre
- Utilisez PushFrame pour démarrer le cadre en cours d'exécution sur le répartiteur
En outre, lorsque vous appelez le désérialiseur lui-même assurez-vous yo u de le faire Dispatcher.BeginInvoke, ou que votre code d'appel ne détient pas de serrures etc.
Voici à quoi il ressemblerait:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Vérification DateTime.Now dans DoEvents() est pas vraiment requis pour que cette technique fonctionne, mais améliorera les performances si SomeProperty est défini très fréquemment lors de la désérialisation. Juste après avoir écrit ceci, j'ai réalisé qu'il existe un moyen plus simple d'implémenter la méthode DoEvents. Au lieu d'utiliser DispatcherFrame, il suffit d'utiliser Dispatcher.Invoke avec une action vide:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
J'ai eu un problème similaire avec mon panneau qui se déplaçait ses éléments. L'interface utilisateur gelait parce que j'utilisais un DispatcherTimer à la priorité Loaded. Le problème est parti dès que je l'ai changé en DispatcherPriority.Input.
- 1. Exécution d'un autre processus sans gel de l'interface utilisateur
- 2. [Threading CLR] Lorsqu'un thread de thread thread bloque, le pool de threads crée des threads supplémentaires
- 3. Threads dans l'espace utilisateur et le rendement
- 4. Exécuter plusieurs threads de l'interface utilisateur
- 5. Dilemna: empêche StackOverflowException ou améliore l'expérience utilisateur?
- 6. CakePHP empêche un utilisateur Entrez l'URL
- 7. ASP Excel.Application objExcel.Range ("range") le gel
- 8. application WPF gel
- 9. Comment obtenir le répartiteur de threads d'interface utilisateur?
- 10. Winforms: éviter l'application gel
- 11. Comment suivre l'application «gel», trouver sa source?
- 12. Pourquoi CoRegisterClassObject crée-t-il deux threads supplémentaires?
- 13. Erreurs d'interface utilisateur d'inter-threads étranges
- 14. Gel intermittent sur iPad
- 15. Gel animation flash
- 16. Empêche Java Applet de gagner le focus
- 17. NSDrawer empêche le redimensionnement
- 18. Android-deux threads changer l'interface utilisateur
- 19. Empêche l'ouverture du disque dur sans mot de passe.
- 20. Gel de l'interface utilisateur avec suppression animée de la sous-vue UIScrollView
- 21. Gel d'un DataGridTextColumn dans WPF
- 22. Chargement du gel GIF parfois
- 23. Application sans Windows, threads et Invoke()
- 24. Vous recherchez des didacticiels sur les threads d'interface utilisateur et les threads de travail
- 25. Le regroupement empêche la virtualisation?
- 26. Faire une division flottante sans installer de gemmes supplémentaires?
- 27. Gel de l'en-tête GridView dans ASP.NET?
- 28. Flex HDividedBox empêche le glissement
- 29. C#: remplissage d'une interface utilisateur à l'aide de threads distincts
- 30. Swing: Empêche CellEditor de perdre le focus
Dans Windows Forms, vous pouvez utiliser Application.DoEvents(). Je ne sais pas si cela fonctionne dans WPF. – Qwertie