【问题标题】:ListBox SelectedIndexChanged event not fired when bound list updates绑定列表更新时未触发 ListBox SelectedIndexChanged 事件
【发布时间】:2018-07-02 12:47:53
【问题描述】:

我想要一个带有关联的添加和删除按钮的基本列表框。当且仅当 ListBox 中有一个选择时,Delete 按钮才会启用,并且 Add 按钮应该将一个项目附加到 ListBox 的末尾。

我的第一次尝试是创建一个List<string> items 字段,如下所示:

public partial class Form1 : Form {
    public Form1 {
        InitializeComponent();
        this.listBox1.DataSource = this.items;
    }

    private void addButton_Click(object sender, EventArgs e) {
        this.items.Add("item {this.items.Count + 1}");
    }

    private void deleteButton_Click(object sender, EventArgs e) {
        this.items.RemoveAt(this.listBox1.SelectedIndex);
    }

    private void listBox1_SelectedIndexChanged(object sender, EventArgs e) {
        this.deleteButton.enabled = (this.listBox1.SelectedIndex != -1);
    }

    List<string> items = new List<string>();
}

但是,事实证明,ListBox 似乎不会随着列表中的项目的变化而自动更新。 Here's a related question 关于它。

大多数建议建议我每次更新列表时只运行listBox1.DataSource = null; this.listBox1.DataSource = this.items;,但这对我来说违背了绑定的目的。

另一个答案建议使用ObservableCollection 作为我列表的数据类型,但这并没有什么不同。

最后我找到了BindingList 类,它似乎做了我想做的事; ListBox 会自动反映items 字段的内容。 (如果有其他解决方案实际上是最佳实践,而不是互联网上粘贴的一些货物崇拜民间传说,请告诉我。)


但是,当我添加到 items 的第一项出现在 ListBox 中时,该行将变为选中状态。我可以看到listBox1.SelectedIndex 从 -1 变为 0。但是,listBox1_SelectedIndexChanged 事件不会触发。因此,删除按钮的状态不会正确更新。

(顺便说一句,这种 UI 模式非常司空见惯,而且在实现如此简单的事情上存在如此多相互矛盾的信息似乎是灾难性的。)

【问题讨论】:

  • 如果我在构造函数中向this.items 添加一个项目,SelectedIndexChanged 回调会触发两次。我赢不了。

标签: c# winforms listbox


【解决方案1】:

我也遇到了同样的问题。由于这是我遇到的第一个问题,也许我的回答会节省一些时间。

DataSource 被分配一个空的BindingList 并且稍后将项目添加到该BindingList 时,如下所示:

private BindingList<MyType> _myList = new BindingList<MyType>();

public MyForm()
{
    listBox1.DataSource = _myList;
}

private void LoadData()
{
    foreach (MyType item in GetDataFromSomewhere())
    {
        _myList.Add(item);
    }
}

然后在添加第一个项目后,将在ListBox 中选择,listBox1.SelectedIndex 将为 0 - 但不会触发 SelectedIndexChanged 事件。

看起来这可能是ListBox 中的一个错误,正如建议的herehere

一种解决方法是从ListBox 派生为Juan did,或者在添加之前检查BindingList 是否包含任何项目:

        bool isFirstItem = (0 == _myList.Count);
        _myList.Add(item);
        if (isFirstItem)
        {
            // Your choice: set listBox1.SelectedIndex to -1 and back to 0,
            // or call the event handler yourself.
        }

【讨论】:

    【解决方案2】:

    尝试手动选择最后一个元素,而不是依赖默认行为。这将触发事件。

    public partial class Form1 : Form
    {
        BindingList<string> items = new BindingList<string>();
        public Form1()
        {
            InitializeComponent();
            this.listBox1.DataSource = items;
        }
    
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.deleteButton.Enabled = (this.listBox1.SelectedIndex != -1);
        }
    
        private void addButton_Click(object sender, EventArgs e)
        {
            this.items.Add($"item {this.items.Count + 1}");
            this.listBox1.SelectedIndex = -1;
            this.listBox1.SelectedIndex = this.listBox1.Items.Count - 1;
        }
    
        private void deleteButton_Click(object sender, EventArgs e)
        {
            this.items.RemoveAt(this.listBox1.SelectedIndex);
        }
    }
    

    【讨论】:

    • 不,此解决方案不起作用。一旦我添加到this.itemsSelectedIndex 就会设置为 0。如果我再次将其设置为 0,则不会触发任何事件。
    • 你是对的。通过将索引设置为-1,然后是最后一项的索引,我能够让它工作。请参阅我的编辑。感觉就像一个黑客,但我想不出另一种方式。编辑:你已经尝试过了
    • 在什么情况下不起作用?该事件正在为我触发
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多