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

时间:2017-02-21 01:59:15

标签: c# winforms listbox .net-4.5

我需要跟踪ListBox上的所选项目,以根据当前选择的值更新/禁用其他控件。

这是重现问题的代码:

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,则SelectedValueChangedSelectedIndexChanged都不会触发上次addButton按,即使您在上一次logSelectionButton按下之前和之后按addButton,也会看到SelectedIndex和{{1}的值已从-1更改为0并从SelectedValue更改为&#34;项目1和#34;分别和那个&#34;项目1&#34;看起来在列表框中选中。

这将导致我需要根据所选项目更新的任何其他控件保持禁用状态,直到用户手动选择列表框中的项目为止,即使第一项已被选中。

我无法想到任何解决方法。也许还订阅我的BindingList的null事件以查看列表是否为空,但我不知道列表框中的项目是否会在我的事件之前或之后更新处理程序触发,这将导致其他问题。

2 个答案:

答案 0 :(得分:4)

好像你在ListControl内部处理PositionChanged事件时发现了一个错误,当数据绑定时(如果在VS中打开例外,当第一项是第一项时,你会看到异常)添加到空列表中。)

由于数据绑定模式中的ListControl派生类(如ListBoxComboBox等)将其选择与Position的{​​{1}}属性同步,因此可靠解决方法(基本上是一个更通用的抽象解决方案)是处理基础数据源绑定管理器的CurrentChanged事件:

BindingManagerBase

答案 1 :(得分:0)

我找到了一个似乎工作正常的解决方法。由于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();
    }
}