8

Tengo un objeto personalizado que implementa INotifyPropertyChanged. Tengo una colección de estos objetos donde la colección se basa en BindingList He creado un origen de enlace para la colección y establezco las fuentes de datos de bindingsource y datagridview.¿Cómo se actualiza correctamente una vista de datos datagrid de un hilo de fondo?

Todo funciona muy bien, excepto que necesito actualizar las propiedades en el objeto personalizado desde los hilos de fondo. cuando lo hago, aparece el siguiente error:

BindingSource no puede ser su propia fuente de datos. No establezca el DataSource y DataMember a valores que informenos de nuevo a BindingSource

me encontré con el siguiente post que parece tener mi problema exacto (y solución?), Pero no acabo de entenderlo.

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

que crea e inicializa las variables oper por el puesto en mi objeto de negocio, y luego puse las dos funciones de eventos en mi clase de colección. Esto compilado correctamente, pero se cuelga sin excepción cuando se ejecuta.

He visto muchas publicaciones que dicen usar Invoke/Begin Invoke, pero no estoy llamando a ninguna función en la interfaz de usuario, simplemente actualizando objetos comerciales, por lo que no estoy seguro de dónde ubicaría las llamadas de invocación.

Una restricción: quiero que el objeto comercial no sepa quién lo muestra (ya que hay varios consumidores), por lo que enviar referencias de GUI al objeto comercial para poder invocar luego utilizando esas referencias no es una opción.

Respuesta

14

Encontré esta clase en un foro que funciona. Sólo tiene que usar esto en vez 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 [Sé que la publicación es antigua pero ... Al crear una instancia de otra lista ThreadedBindingList (mi lista), no hay un método para esto. ¿No debería estar el método allí para que sea 'completo' o habría un problema de enhebrado? – Stix

1

Desde que se tomó el tiempo para dar formato a la muestra para mis necesidades que también podría publicar aquí como una referencia legible. Nada cambió excepto el formateo.

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

hilo No del todo seguro, pero este pequeño cambio en las respuestas anteriores podría tener un gran impacto si el subproceso de fondo es la modificación de las propiedades del objeto más rápido que el que se puede mostrar;

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); 
    } 
} 

bienvenida a cualquier sugerencia para reducir el número de llamadas publicadas si el mismo objeto se ha modificado más de una vez, y asegurarse de que cualquier tarde enviar la llamada se bloqueará hasta que se han procesado todas las llamadas publicados.

Cuestiones relacionadas