首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >BindingList<> ListChanged事件

BindingList<> ListChanged事件
EN

Stack Overflow用户
提问于 2009-08-29 10:55:22
回答 2查看 17.4K关注 0票数 19

我将一个类的BindingList<>设置为BindingSource的DataSource属性,该属性又设置为DataGridView的DataSource属性。

  1. 我的理解是,任何添加到列表中的内容都将触发一个ListChanged事件,该事件将通过BindingSource传播,然后传递到DataGridView上,该事件将自我更新以显示更改。这将会发生,因为事件已被自动挂钩。(是?)

当所有工作都在UI线程上完成时,这一切都很好,但是当创建列表并从非UI线程更改列表时,当网格更新时,最终会发生跨线程异常。我可以理解为什么会发生这种情况,但不知道如何修复它。

  1. 我很难理解的是,我应该在哪里最好地截取ListChanged事件,以尝试将内容编组到UI线程上?我猜我需要一个对UI线程的引用来帮助实现这一点--

我读过很多关于这方面的文章,但我还在苦苦挣扎,因为我不能完全理解这里的工作机制。

我永远不会改变任何项目,一旦它们在列表中,我只会添加它们,并最初清除列表。

(我使用的是.NET 2.0)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-08-29 16:55:29

您可以扩展BindingList以使用ISynchronizeInvoke (由System.Windows.Forms.Control实现)来将事件调用编组到UI线程上。

然后,您需要做的就是使用新的列表类型,所有内容都已排序。

代码语言:javascript
复制
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);
    }
}
票数 28
EN

Stack Overflow用户

发布于 2009-08-29 13:59:59

  1. 认为这个观点是足够公平的。在幕后,CurrencyManager和Binding等其他对象确保在底层数据源将项changes.
  2. Adding到数据绑定BindingList触发一系列事件时更新控件,这些事件最终会尝试更新DataGridView。由于UI只能从UI线程更新,因此应通过Control.Invoke.

将项目从UI线程添加到BindingList

我组装了一个快速示例,创建了一个包含DataGridView、BindingSource和Button的表单。

该按钮启动另一个线程,该线程模拟获取要包含在BindingList中的新项。

包含本身是通过Control.Invoke在UI线程中完成的。

代码语言:javascript
复制
    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; }
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1351138

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档