2017-08-31 49 views
1

給定一個非常簡單的設置:一個ComboBox應該由BindingList<string>填充。顯然,SelectedValueChangedSelectedIndexChanged事件是非常重要的。但他們都表現得很奇怪:關於BindingList作爲ComboBox數據源Puzzeled

  1. 該列表最初是空的。
  2. 在添加第一項時,我會收到兩個連續的SelectedValueChanged事件。爲什麼有兩個事件而不是一個,即使報告的值在這兩個事件之間沒有變化?與此同時,即使索引剛剛從-1更改爲0,SelectedIndexChanged事件也會丟失。
  3. 添加其他項目。現在,即使所選值實際保持不變,我也會爲每個添加的項目收到一個單獨的SelectedValueChanged事件。但是,沒有SelectedIndexChanged事件。但這是預期的,因爲選定的指數在這裏不會改變。
  4. 刪除列表末尾的項目。即使沒有發生實際變化,我仍然會收到SelectedValueChanged事件。雖然我沒有看到SelectedIndexChanged事件。
  5. 刪除最後一個項目(實際上仍然是選定的項目)。正如我所期望的那樣,現在我得到了兩個,分別是SelectedValueChangedSelectedIndexChanged
  6. 再次添加新項目。現在它變得非常奇怪。該項目被添加,因爲它是列表中唯一被選中的項目。 ComboBox按預期報告(SelectedValue爲「Item 1」,SelectedIndex爲0)。但是現在我沒有收到任何改變的事件,無論是價值還是索引。
  7. 添加更多項目。我沒有收到有關將項目添加到初始列表(步驟3)的(非預期)事件。

因爲我不希望SELECT被打破,請指出我在這裏失蹤的內容。

請注意(關於@Alex Horlock的答案):在本示例中,組合框選擇僅受到向數據源添加/刪除項目或從數據源刪除項目的影響。交互式更改ComboBox中的選定項目的行爲與預期相同。

下面是樣本Form1的代碼(含組合框和三個按鈕(添加/刪除/狀態):

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}]"); 
     } 
    } 
} 
+0

事實上,SELECT似乎在這裏被打破。在組合框代碼深處,有一個名爲'selectedValueChangedFired'的私有標誌,當列表變空並向其添加新項目時,該標誌不能正確重置。只有在用戶與ComboBox交互時纔會重置。 – freefall

回答

0

的組合框.NET框架的代碼有一個專用標記存儲關於變更事件的信息已經被解僱該標誌只有在找到實施ICurrencyManagerProvider的數據源時纔會重置。不幸的是,BindingList<T>沒有實現這個接口。好消息是BindingSource確實實現了它。因此,所有我必須做的是放置一個BindingSource在ComboBox和BindingList<T>,這樣之間:

  • 我簡單地從工具箱中投下了BindingSource到窗體。
  • 在窗體的構造,我換成

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

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

該做的伎倆。

還有一些重複和不相關的事件被解僱。然而,這個解決方案是在步驟6中發射事件,它曾經是原始版本中的顯示屏。

0

我不知道爲什麼所有這些事件觸發的順序,但我想你要使用selectionChangeCommitted事件來避免此類問題的

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

+0

'SelectionChangeCommitted'似乎只有在選擇交互改變時纔會被觸發。在這裏,選擇僅僅通過向數據源添加和刪除項目來改變。無論如何,交互式更改會激發正確的事件。 – freefall