8

J'ai un objet personnalisé qui implémente INotifyPropertyChanged. J'ai une collection de ces objets où la collection est basée sur BindingList J'ai créé une source de liaison pour la collection, et définir les sources de données de la bindingsource et de la datagridview.Comment mettre à jour correctement une datagridview databound à partir d'un thread d'arrière-plan

Tout fonctionne très bien, sauf que j'ai besoin de mettre à jour les propriétés de l'objet personnalisé à partir des threads d'arrière-plan. lorsque je le fais, j'obtiens l'erreur suivante:

BindingSource ne peut pas être sa propre source de données. Ne pas définir les propriétés DataSource et DataMember à des valeurs Référé retour à BindingSource

J'ai trouvé le post suivant qui semble avoir mon problème exact (et solution?) Mais je ne peux pas comprendre tout à fait dehors.

http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/3566f7c7-eb47-422e-ab09-9549a18da360/

J'ai créé et initialisé les variables oper par poste dans mon objet métier, puis je mets les deux fonctions d'événement dans ma classe de collection. Cela compilé correctement, mais se bloque sans exception lors de l'exécution.

J'ai vu beaucoup de messages disant d'utiliser Invoke/Begin Invoke, mais je n'appelle aucune fonction sur l'interface utilisateur, je ne fais que mettre à jour des objets métier, donc je ne suis pas sûr d'où je pourrais appeler. Une restriction: Je souhaite que l'objet métier ne sache pas qui l'affiche (car il y a plusieurs consommateurs). L'envoi de références GUI dans l'objet métier pour pouvoir ensuite appeler invoke à l'aide de ces références n'est pas possible. une option.

Répondre

14

J'ai trouvé cette classe dans un forum qui fonctionne. Il suffit d'utiliser ce lieu de BindingList

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

using System.ComponentModel; 
using System.Threading; 

namespace Utility 
{ 
    public class ThreadedBindingList<T> : BindingList<T> 
    { 
     SynchronizationContext ctx = SynchronizationContext.Current; 

     protected override void OnAddingNew(AddingNewEventArgs e) 
     { 

      if (ctx == null) 
      { 
       BaseAddingNew(e); 
      } 
      else 
      { 
       ctx.Send(delegate 
       { 
        BaseAddingNew(e); 
       }, null); 
      } 
     } 
     void BaseAddingNew(AddingNewEventArgs e) 
     { 
      base.OnAddingNew(e); 
     } 
     protected override void OnListChanged(ListChangedEventArgs e) 
     { 
      // SynchronizationContext ctx = SynchronizationContext.Current; 
      if (ctx == null) 
      { 
       BaseListChanged(e); 
      } 
      else 
      { 
       ctx.Send(delegate 
       { 
        BaseListChanged(e); 
       }, null); 
      } 
     } 
     void BaseListChanged(ListChangedEventArgs e) 
     { 
      base.OnListChanged(e); 
     } 
    } 
} 
+0

@Marc Gravell [Je sais que le message est ancien mais ..Lors de l'instanciation d'une autre liste ThreadedBindingList de liste (mon Ilist) - il n'y a pas de méthode pour cela. La méthode ne devrait-elle pas être là pour que cela soit «complet» ou y aurait-il un problème de threading? – Stix

1

Depuis que je pris le temps de formater l'échantillon pour mes besoins je pourrais aussi bien poster ici comme une référence lisible. Rien n'a changé sauf le formatage.

using System.ComponentModel; 
using System.Threading; 

namespace Utility 
{ 
    public class ThreadedBindingList : BindingList 
    { 
    SynchronizationContext ctx = SynchronizationContext.Current; 
    protected override void OnAddingNew(AddingNewEventArgs e) 
    { 
     if (ctx == null) 
     { 
     BaseAddingNew(e); 
     } 
     else 
     { 
     ctx.Send(delegate { BaseAddingNew(e); }, null); 
     } 
    } 

    void BaseAddingNew(AddingNewEventArgs e) 
    { 
     base.OnAddingNew(e); 
    } 

    protected override void OnListChanged(ListChangedEventArgs e) 
    { 
     // SynchronizationContext ctx = SynchronizationContext.Current; 
     if (ctx == null) 
     { 
     BaseListChanged(e); 
     } 
     else 
     { 
     ctx.Send(delegate { BaseListChanged(e); }, null); 
     } 
    } 

    void BaseListChanged(ListChangedEventArgs e) 
    { 
     base.OnListChanged(e); 
    } 
    } 
} 
0

Pas tout à fait thread-safe, mais ce petit changement des réponses ci-dessus pourrait avoir un impact important si votre thread d'arrière-plan est en train de modifier les propriétés des objets plus rapidement qu'elles ne peuvent être affichés;

protected override void OnListChanged(ListChangedEventArgs e) 
{ 
    // SynchronizationContext ctx = SynchronizationContext.Current; 
    if (ctx == null) 
    { 
    BaseListChanged(e); 
    } 
    else if(e.ListChangedType == ListChangedType.ItemChanged) 
    { 
    ctx.Post(delegate { BaseListChanged(e); }, null); 
    } 
    else 
    { 
    ctx.Send(delegate { BaseListChanged(e); }, null); 
    } 
} 

Bienvenue suggestions pour réduire le nombre d'appels affichés si le même objet a été modifié plus d'une fois, et de faire envoyer que tout appel plus tard bloquera jusqu'à ce que ont été traités tous les appels affichés.

Questions connexes