C# 关于BindingList作为组合框数据源的争论

C# 关于BindingList作为组合框数据源的争论,c#,winforms,data-binding,combobox,C#,Winforms,Data Binding,Combobox,给出一个非常简单的设置:一个组合框应该由一个BindingList填充。显然,SelectedValueChanged和selectedindex changed事件非常重要。但他们的行为都很奇怪: 列表最初为空。 在添加第一项时,我收到两个连续的SelectedValueChanged事件。为什么有两个事件而不是一个,即使报告的值在这两个事件之间没有变化?同时,SelectedIndexChanged事件丢失,即使索引刚刚从-1更改为0 添加其他项目。现在,对于添加的每个项目,我都会收到一个S

给出一个非常简单的设置:一个组合框应该由一个
BindingList
填充。显然,
SelectedValueChanged
selectedindex changed
事件非常重要。但他们的行为都很奇怪:

  • 列表最初为空。
  • 在添加第一项时,我收到两个连续的
    SelectedValueChanged
    事件。为什么有两个事件而不是一个,即使报告的值在这两个事件之间没有变化?同时,
    SelectedIndexChanged
    事件丢失,即使索引刚刚从-1更改为0
  • 添加其他项目。现在,对于添加的每个项目,我都会收到一个
    SelectedValueChanged
    事件,即使所选值实际上保持不变。但是,没有选择索引更改的
    事件。但这是意料之中的,因为此处所选索引没有更改
  • 从列表末尾删除项目。即使没有发生实际的更改,我也会不断收到
    SelectedValueChanged
    事件。但是,我没有看到
    SelectedIndexChanged
    事件
  • 删除最后一项(实际上仍然是选定项)。现在我得到了我所期望的,
    SelectedValueChanged
    selectedindex changed
  • 再次添加新项目。现在它变得很奇怪。将添加该项目,因为它是列表中唯一的项目,所以将选中该项目。组合框按预期报告它(
    SelectedValue
    为“项目1”,而
    SelectedIndex
    为0)。但是现在我没有收到任何更改的事件,无论是值还是索引
  • 添加更多项目。我没有收到在将项目添加到初始列表(步骤3)时收到的(非预期)
    SelectecValueChanged
    事件
  • 由于我不希望SELECT被破坏,请告诉我这里缺少什么

    请注意(关于@Alex Horlock的答案):在本示例中,组合框选择仅受向数据源添加/删除项的影响。在组合框中以交互方式更改选定项的行为符合预期

    下面是示例Form1的代码(包含一个组合框和三个按钮(添加/删除/状态):

    名称空间绑定测试
    {
    使用制度;
    使用系统组件模型;
    使用System.Linq;
    使用System.Windows.Forms;
    公共部分类Form1:Form
    {
    公共表格1()
    {
    初始化组件();
    comboBox1.DataSource=新绑定列表();
    }
    私有无效按钮1\u单击(对象发送者,事件参数e)
    {
    var dataSource=comboBox1.dataSource作为BindingList;
    dataSource?.Add($“Item{dataSource.Count+1}”);
    }
    私有无效按钮2\u单击(对象发送者,事件参数e)
    {
    var dataSource=comboBox1.dataSource作为BindingList;
    如果(数据源?.Count>0)
    {
    删除(dataSource.Last());
    }
    }
    私有无效按钮3\u单击(对象发送者,事件参数e)
    {
    WriteLine($“SelectedValue:{comboBox1.SelectedValue}”);
    WriteLine($“SelectedIndex:{comboBox1.SelectedIndex}”);
    }
    私有无效组合框1\u SelectedIndexChanged(对象发送方,事件参数e)
    {
    var dataSource=comboBox1.dataSource作为BindingList;
    WriteLine($“SelectedINDEXChanged:{comboBox1.SelectedIndex}[{dataSource?.Count}]”);
    }
    private void comboBox1\u SelectedValueChanged(对象发送方,事件参数e)
    {
    var dataSource=comboBox1.dataSource作为BindingList;
    WriteLine($“SelectedVALUEChanged:{comboBox1.SelectedValue}[{dataSource?.Count}]”);
    }
    }
    }
    
    我不确定为什么所有这些事件都会按该顺序触发,但我认为您希望使用selectionChangeCommitted事件来避免此类问题


    请参见-()

    我不确定为什么所有这些事件都会按该顺序触发,但我认为您希望使用selectionChangeCommitted事件来避免此类问题


    见-()

    ComboBox的.NET Framework代码维护一个私有标志,用于存储有关已触发的更改事件的信息。只有在发现数据源实现了
    ICurrencyManagerProvider
    时,才会重置此标志。不幸的是,
    BindingList
    没有实现此接口。好消息是
    BindingSource
    确实实现了它。所以我所要做的就是在组合框和
    绑定列表之间放置一个
    BindingSource
    ,如下所示:

    • 我只是从工具箱中将一个
      BindingSource
      放到表单上
    • 在窗体的构造函数中,我替换了

      comboBox1.DataSource = new BindingList<string>();
      
      comboBox1.DataSource=newbindingList();
      

      bindingSource1.DataSource=newbindingList();
      comboBox1.DataSource=bindingSource1;
      
    这就成功了


    仍有许多重复和不相关的事件被激发。但是,此解决方案在步骤6中激发事件,这在原始版本中曾经是显示的止动符。

    ComboBox的.NET Framework代码维护一个私有标志,存储有关已激发的更改事件的信息。此标志只有在找到时才会重置实现
    ICurrencyManagerProvider
    的数据源。不幸的是,
    BindingList
    没有实现此接口。好消息是
    BindingSource
    确实实现了它。所以我所要做的就是在组合框和
    BindingList
    之间放置一个
    BindingSource
    ,如下所示:

    • 我只是从工具箱中将一个
      BindingSource
      放到表单上
    • comboBox1.DataSource = new BindingList<string>();
      
      bindingSource1.DataSource = new BindingList<string>();
      comboBox1.DataSource = bindingSource1;