Managed it by educating BindingList<T> about sync-context; a "keeper" I
reckon ;-p
Most of this code is demo; it is just the list that you need...
Marc
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public abstract class EntityBase : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
protected virtual bool UpdateField<T>(ref T field, T value, string
propertyName) {
if (EqualityComparer<T>.Default.Equals(field, value)) return
false; // no change
field = value;
if (!string.IsNullOrEmpty(propertyName))
OnPropertyChanged(propertyName);
return true;
}
protected virtual void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class SomeEntity : EntityBase
{
public SomeEntity() { }
public SomeEntity(string forename, string surname, DateTime
dateOfBirth)
{
Forename = forename;
Surname = surname;
DateOfBirth = dateOfBirth;
}
private string forename, surname;
private DateTime dateOfBirth;
public string Forename {
get { return forename; }
set { UpdateField(ref forename, value, "Forename"); }
}
public string Surname {
get { return surname; }
set { UpdateField(ref surname, value, "Surname"); }
}
public DateTime DateOfBirth {
get { return dateOfBirth; }
set { UpdateField(ref dateOfBirth, value, "DateOfBirth"); }
}
}
static class Program
{
[STAThread]
static void Main()
{
ThreadedBindingList<SomeEntity> data = new
ThreadedBindingList<SomeEntity>();
data.Add(new SomeEntity());
data.Add(new SomeEntity());
data.Add(new SomeEntity());
Application.EnableVisualStyles();
using(Form f = new Form())
using (DataGridView dgv = new DataGridView())
{
dgv.Dock = DockStyle.Fill;
dgv.DataSource = data;
f.Controls.Add(dgv);
f.Load += delegate {
ThreadPool.QueueUserWorkItem(delegate
{
StartRandomEditing(data);
});
};
Application.Run(f);
}
}
static void StartRandomEditing(IList<SomeEntity> data)
{
Random rand = new Random();
while (true)
{
Thread.Sleep(1000);
int index = rand.Next(data.Count);
SomeEntity item = data[index];
switch (rand.Next(3))
{
case 0:
item.Forename += "#";
break;
case 1:
item.Surname += "#";
break;
case 2:
item.DateOfBirth += TimeSpan.FromDays(1);
break;
}
}
}
}
public class ThreadedBindingList<T> : BindingList<T>
{
protected override void OnAddingNew(AddingNewEventArgs e)
{
SynchronizationContext ctx = SynchronizationContext.Current;
if (ctx == null)
{
BaseAddingNew(e);
}
else
{
SynchronizationContext.Current.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
{
SynchronizationContext.Current.Send(delegate
{
BaseListChanged(e);
}, null);
}
}
void BaseListChanged(ListChangedEventArgs e)
{
base.OnListChanged(e);
}
}
}