我将一个类的BindingList<>设置为BindingSource的DataSource属性,该属性又设置为DataGridView的DataSource属性。
当所有工作都在UI线程上完成时,这一切都很好,但是当创建列表并从非UI线程更改列表时,当网格更新时,最终会发生跨线程异常。我可以理解为什么会发生这种情况,但不知道如何修复它。
我读过很多关于这方面的文章,但我还在苦苦挣扎,因为我不能完全理解这里的工作机制。
我永远不会改变任何项目,一旦它们在列表中,我只会添加它们,并最初清除列表。
(我使用的是.NET 2.0)
发布于 2009-08-29 16:55:29
您可以扩展BindingList以使用ISynchronizeInvoke (由System.Windows.Forms.Control实现)来将事件调用编组到UI线程上。
然后,您需要做的就是使用新的列表类型,所有内容都已排序。
public partial class Form1 : System.Windows.Forms.Form {
SyncList<object> _List;
public Form1() {
InitializeComponent();
_List = new SyncList<object>(this);
}
}
public class SyncList<T> : System.ComponentModel.BindingList<T> {
private System.ComponentModel.ISynchronizeInvoke _SyncObject;
private System.Action<System.ComponentModel.ListChangedEventArgs> _FireEventAction;
public SyncList() : this(null) {
}
public SyncList(System.ComponentModel.ISynchronizeInvoke syncObject) {
_SyncObject = syncObject;
_FireEventAction = FireEvent;
}
protected override void OnListChanged(System.ComponentModel.ListChangedEventArgs args) {
if(_SyncObject == null) {
FireEvent(args);
}
else {
_SyncObject.Invoke(_FireEventAction, new object[] {args});
}
}
private void FireEvent(System.ComponentModel.ListChangedEventArgs args) {
base.OnListChanged(args);
}
}发布于 2009-08-29 13:59:59
将项目从UI线程添加到BindingList
我组装了一个快速示例,创建了一个包含DataGridView、BindingSource和Button的表单。
该按钮启动另一个线程,该线程模拟获取要包含在BindingList中的新项。
包含本身是通过Control.Invoke在UI线程中完成的。
public partial class BindingListChangedForm : Form {
BindingList<Person> people = new BindingList<Person>();
Action<Person> personAdder;
public BindingListChangedForm() {
InitializeComponent();
this.dataGridView1.AutoGenerateColumns = true;
this.bindingSource1.DataSource = this.people;
this.personAdder = this.PersonAdder;
}
private void button1_Click(object sender, EventArgs e) {
Thread t = new Thread(this.GotANewPersononBackgroundThread);
t.Start();
}
// runs on the background thread.
private void GotANewPersononBackgroundThread() {
Person person = new Person { Id = 1, Name = "Foo" };
//Invokes the delegate on the UI thread.
this.Invoke(this.personAdder, person);
}
//Called on the UI thread.
void PersonAdder(Person person) {
this.people.Add(person);
}
}
public class Person {
public int Id { get; set; }
public string Name { get; set; }
}https://stackoverflow.com/questions/1351138
复制相似问题