2

J'ai une application WPF qui affiche une ObservableCollection. C'est environ 182 lignes, et l'objet (appelons-le PositionLight) à l'intérieur de la collection a environ 70 propriétés à afficher.GUI gelée pendant la mise à jour de mon ObservableCollection

Tous les calculs pour entrer des données dans ces propriétés sont effectués dans un deuxième thread qui va tout recalculer toutes les 20 secondes, et enverra une liste à la fenêtre WPF, thx à un événement. De cette façon, le calcul ne ralentit pas l'interface graphique.

La liste est transformée en ObservableCollection dans le constructeur des EventArgs envoyés avec l'événement à GIU.

Le problème est même quand j'utiliser un BeginInvoke et un délégué à faire:

myGUICollection = myEventArgsCollection

l'interface graphique sera gelé pendant 3 à 4 secondes ... J'ai mis beaucoup de Console.Writeline pour savoir où est le goulot d'étranglement, mais il semble que le gel se produira juste après qu'il ait quitté la fonction appelée par BeginInvoke. Je suis vraiment perdu ici. J'utilise un PC 4 core avec 2,5 Go de RAM, donc je ne pense pas que ce soit un problème matériel.

Avez-vous une idée?

code pour vous donner une meilleure idée de l'insert dans l'interface graphique:

public bool myCoreScope_OnCoreCalculationHandler(object myObject, CoreCalculationEventArgs myEventArgs) 
    { 

     foreach (PositionLight item in myEventArgs.MyPositionList) 
     { 
      lv.Dispatcher.BeginInvoke(new DisplayPositionItemCallBack(DisplayPositionItem), DispatcherPriority.Send, new object[] { item }); 
     } 

    } 


    private delegate void DisplayPositionItemCallBack(PositionLight item); 

    private void DisplayPositionItem(PositionLight item) 
    { 
     try 
     { 
      MyPositionList.Remove(MyPositionList.First(position => position.ID== item.ID)); 
     } 
     catch (Exception) 
     { } 
     MyPositionList.Add(item); 
    } 
+0

Publiez du code supplémentaire pour analyser – TalentTuner

+0

@saurabh: done. Je ai pris en compte ce que Fara a dit, mais toujours finir avec le même temps de congélation – Gregfr

Répondre

2

Lorsque vous appelez BeginInvoke vous rassemblons la mise à jour ObservableCollection sur le fil de l'interface graphique, et bien que le calcul peut se produire sur un thread séparé la mise à jour de l'interface utilisateur ne fonctionne pas. Si vous appelez une mise à jour coûteuse sur le thread graphique, le thread devra attendre jusqu'à ce que cette opération soit terminée.

Une approche alternative consiste à effectuer une invocation pour chaque élément de la collection, plutôt que la totalité de la collection à la fois, ce qui donnera au GUI le temps de traiter ses autres messages entre les mises à jour.

var list = GetCollection(); 
foreach (var item in list) 
{ 
    Dispatcher.BeginInvoke(new Action(() => myGuiCollection.Add(item))); 
} 

Une autre option, vous pouvez essayer est de définir l'attribut IsAsync de l'ItemsSource données obligatoire.

<ListBox ItemsSource="{Binding myGuiCollection, IsAsync=True}" /> 
+0

ce que vous dites n'a de sens, cependant, en ajoutant un élément par un moyen je dois d'abord trouver l'ancien élément, le retirer, puis ajouter le nouveau un. J'ai peur que cela n'accélère pas le processus. Je vais essayer malgré tout – Gregfr

+0

GOT IT! Au lieu de supprimer et d'insérer un nouvel élément, je mets à jour chaque élément existant, un par un. On dirait que ça utilise beaucoup moins de CPU, et l'interface graphique n'est plus figée. Je vais laisser le sujet ouvrir quelques heures juste pour confirmer qu'il fonctionne correctement – Gregfr

+0

Ah OK, je pensais plus à l'initialisation de la collection, pas à sa mise à jour. Pour mettre à jour les éléments liés à l'interface utilisateur, vous devez consulter l'interface INotifyPropertyChanged. C'est la meilleure façon de faire ce genre de chose. –