将BindingList作为ComboBox数据源进行了解

时间:2017-08-31 08:23:22

标签: c# winforms data-binding combobox

给定一个非常简单的设置:ComboBox应由BindingList<string>填充。显然,SelectedValueChangedSelectedIndexChanged事件非常重要。但他们都表现得很奇怪:

  1. 该列表最初为空。
  2. 在添加第一个项目时,我会收到两个连续的SelectedValueChanged个事件。为什么有两个事件而不是一个,即使报告的值在这两个事件之间没有变化?同时,即使索引从-1更改为0,也会丢失SelectedIndexChanged事件。
  3. 添加其他商品。现在,我为每个添加的项目收到一个SelectedValueChanged个事件,即使所选值实际上保持不变。但是没有SelectedIndexChanged个事件。但这是预期的,因为所选索引在这里没有变化。
  4. 从列表末尾删除项目。即使没有发生实际变化,我仍然会收到SelectedValueChanged个事件。但是,我没有看到SelectedIndexChanged个事件。
  5. 删除最后一项(实际上仍是选定的项目)。现在我得到了SelectedValueChangedSelectedIndexChanged,正如我所料。
  6. 再次添加新项目。现在它变得非常奇怪。该项目已添加,因为它是列表中唯一的项目。 ComboBox按预期报告(SelectedValue为“项目1”,SelectedIndex为0)。但是现在我没有收到任何Changed事件,无论是值还是索引。
  7. 添加更多内容。我没有收到在将项目添加到初始列表时收到的(非预期的)SelectecValueChanged事件(步骤3)。
  8. 由于我不希望SELECT被打破,请指出我在这里缺少的东西。

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

    以下是示例Form1的代码(包含ComboBox和三个按钮(添加/删除/状态):

    namespace BindingTest
    {
        using System;
        using System.ComponentModel;
        using System.Linq;
        using System.Windows.Forms;
    
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
                comboBox1.DataSource = new BindingList<string>();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                var dataSource = comboBox1.DataSource as BindingList<string>;
                dataSource?.Add($"Item {dataSource.Count + 1}");
            }
    
            private void button2_Click(object sender, EventArgs e)
            {
                var dataSource = comboBox1.DataSource as BindingList<string>;
                if (dataSource?.Count > 0)
                {
                    dataSource.Remove(dataSource.Last());
                }
            }
    
            private void button3_Click(object sender, EventArgs e)
            {
                Console.WriteLine($"SelectedValue: {comboBox1.SelectedValue}");
                Console.WriteLine($"SelectedIndex: {comboBox1.SelectedIndex}");
            }
    
            private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
            {
                var dataSource = comboBox1.DataSource as BindingList<string>;
                Console.WriteLine($"SelectedINDEXChanged: {comboBox1.SelectedIndex} [{dataSource?.Count}]");
            }
    
            private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
            {
                var dataSource = comboBox1.DataSource as BindingList<string>;
                Console.WriteLine($"SelectedVALUEChanged: {comboBox1.SelectedValue} [{dataSource?.Count}]");
            }
        }
    }
    

2 个答案:

答案 0 :(得分:0)

我不确定为什么所有这些事件按此顺序触发,但我认为你想使用selectionChangeCommitted事件来避免这种类型的问题。

见 - (https://msdn.microsoft.com/en-us/library/system.windows.forms.combobox.selectionchangecommitted(v=vs.110).aspx

答案 1 :(得分:0)

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

  • 我只是将BindingSource从工具箱中删除到表单上。
  • 在表单的构造函数中,我替换了

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

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

这就是诀窍。

仍有许多重复和无关的事件被解雇。但是,这个解决方案是在步骤6中触发事件,这曾是原始版本中的显示停止。