2017-02-21 110 views
4

我需要保持在列表框軌道所選擇的項目的根據當前所選的值來更新/禁用其它控制/的SelectedIndexChanged不點火。列表框SelectedValueChanged當數據源改變

這是重現該問題的代碼:

public partial class Form1 : Form 
{ 
    private readonly BindingList<string> List = new BindingList<string>(); 

    public Form1() 
    { 
     InitializeComponent(); 
     listBox1.DataSource = List; 

     listBox1.SelectedValueChanged += (s, e) => System.Diagnostics.Debug.WriteLine("VALUE"); 
     listBox1.SelectedIndexChanged += (s, e) => System.Diagnostics.Debug.WriteLine("INDEX"); 

     addButton.Click += (s, e) => List.Add("Item " + (List.Count + 1)); 
     removeButton.Click += (s, e) => List.RemoveAt(List.Count - 1); 

     logSelectionButton.Click += (s, e) => 
     { 
      System.Diagnostics.Debug.WriteLine("Selected Index: " + listBox1.SelectedIndex); 
      System.Diagnostics.Debug.WriteLine("Selected Value: " + listBox1.SelectedValue); 
     }; 
    } 
} 

我的窗體有一個列表框listBox1和三個按鈕:addButtonremoveButtonlogSelectionButton

如果按addButton(從一個空列表),然後removeButton最後addButton再次,既不SelectedValueChanged也不SelectedIndexChanged將火在最後addButton機,即使你之前和最後addButton按後按logSelectionButton,你就會發現兩者SelectedIndexSelectedValue的值已經從-1變爲0,並從null分別爲‘項目1’,並認爲‘項目1’看起來在列表框中選擇。

這將導致我需要根據所選擇的項目更新任何其他控件保持禁用,直到用戶手動選擇在列表框中的項目,即使第一個項目已經被選中。

我想不出什麼解決辦法的。也許還訂閱我的BindingList的ListChanged事件看列表是否爲空,但我不知道,如果在列表框中的項目會前或我的事件處理程序火災,這將導致其他問題後進行更新。

回答

3

好像在ListControl內部處理PositionChanged事件時發現了一個錯誤,當數據綁定時(如果您在VS中打開Exceptions,當第一個項目被添加到空列表中時會看到一個異常)。

由於ListControl派生類等ListBoxComboBox等在綁定模式數據同步它們與BindingManagerBasePosition屬性,可靠的解決辦法(和基本上是一個更通用的抽象的溶液)的選擇是處理CurrentChanged事件底層數據的源綁定管理器:

listBox1.BindingContext[List].CurrentChanged += (s, e) => 
    System.Diagnostics.Debug.WriteLine("CURRENT"); 
+0

這似乎並沒有工作。顯然'CurrentChanged'在選擇實際改變之前觸發,我需要的是跟蹤當前選擇的項目。我找到了另一種解決方案(請參閱我自己的回覆) – Juan

+0

如你所願。如果通過綁定管理器的「當前」屬性提供相同的控制選擇,並且是正確的,我不明白爲什麼你會關心。所有自動主 - 細節綁定和導航器都使用該方法,而不是對特定的控件事件/屬性作出反應。 –

+0

不知道你可以從'Current'中獲得選定的值。好的方法。 – Juan

0

我發現一個解決方法,似乎工作正常。由於列表框通過設置SelectedIndex屬性更新所選指數和財產是虛擬的,我可以重寫它來跟蹤它:

public class ListBoxThatWorks : ListBox 
{ 
    private int LatestIndex = -1; 
    private object LatestValue = null; 

    public EqualityComparer<object> ValueComparer { get; set; } 

    public override int SelectedIndex 
    { 
     get { return base.SelectedIndex; } 
     set { SetSelectedIndex(value); } 
    } 

    private void NotifyIndexChanged() 
    { 
     if (base.SelectedIndex != LatestIndex) 
     { 
      LatestIndex = base.SelectedIndex; 
      base.OnSelectedIndexChanged(EventArgs.Empty); 
     } 
    } 

    private void NotifyValueChanged() 
    { 
     if (!(ValueComparer ?? EqualityComparer<object>.Default).Equals(LatestValue, base.SelectedValue)) 
     { 
      LatestValue = base.SelectedValue; 
      base.OnSelectedValueChanged(EventArgs.Empty); 
     } 
    } 

    private void SetSelectedIndex(int value) 
    { 
     base.SelectedIndex = value; 
     NotifyIndexChanged(); 
     NotifyValueChanged(); 
    } 
}