简体   繁体   English

列表框SelectedValueChanged / SelectedIndexChanged在数据源更改时不触发

[英]ListBox SelectedValueChanged/SelectedIndexChanged not firing when data source changes

I need to keep track of the selected item on a ListBox to update/disable other controls according to the currently selected value. 我需要跟踪ListBox上的所选项目,以根据当前选择的值更新/禁用其他控件。

This is the code to reproduce the issue: 这是重现问题的代码:

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);
        };
    }
}

My form has a list box listBox1 and three buttons: addButton , removeButton and logSelectionButton . 我的表单有一个列表框listBox1和三个按钮: addButtonremoveButtonlogSelectionButton

If you press addButton (starting with an empty list), then removeButton and finally addButton again, neither SelectedValueChanged nor SelectedIndexChanged will fire at the last addButton press, even though if you press logSelectionButton before and after the last addButton press, you'll see that the values of both SelectedIndex and SelectedValue have changed from -1 to 0 and from null to "Item 1" respectively, and that "Item 1" looks selected on the list box. 如果按addButton (从一个空列表),然后removeButton最后addButton再次,既不SelectedValueChanged也没有SelectedIndexChanged会触发在最后addButton按下,即使如果按logSelectionButton前后历时后addButton按下,你会看到SelectedIndexSelectedValue的值分别从-1变为0,从null变为“Item 1”,并且在列表框中看起来选择了“Item 1”。

This would cause any other controls I need to update according to the selected item to stay disabled until the user manually selects an item on the list box, even though the first item is already selected. 这将导致我需要根据所选项目更新任何其他控件以保持禁用状态,直到用户手动选择列表框中的项目为止,即使第一项已被选中。

I can't think of any workaround. 我想不出任何解决方法。 Perhaps also subscribing to my BindingList's ListChanged event to see whether the list is empty or not, but then I don't know if the items in the list box will be updated before or after my event handler fires, which will cause other problems. 也许还订阅我的BindingList的ListChanged事件以查看列表是否为空,但后来我不知道列表框中的项是否会在事件处理程序触发之前或之后更新,这将导致其他问题。

Seems like you found a bug in ListControl internal handling of the PositionChanged event when data bound (if you turn Exceptions on in VS, you'll see an exception when the first item is added to the empty list). 好像你发现一个bug ListControl中的内部处理PositionChanged当数据绑定事件(如果启用例外在VS,你会看到一个异常时,第一项被添加到空列表)。

Since ListControl derived classes like ListBox , ComboBox etc. in data bound mode synchronize their selection with the Position property of the BindingManagerBase , the reliable workaround (and basically a more general abstract solution) is to handle CurrentChanged event of the underlying data source binding manager: 由于ListControl派生类(如ListBoxComboBox等)在数据绑定模式下将它们的选择与BindingManagerBasePosition属性同步,因此可靠的解决方法(基本上是更通用的抽象解决方案)是处理基础数据源绑定管理器的CurrentChanged事件:

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

I found a workaround that seems to work fine. 我找到了一个似乎工作正常的解决方法。 Since ListBox updates the selected index by setting the SelectedIndex property and the property is virtual I can override it to keep track of it: 由于ListBox通过设置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();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM