如何检测是不是将项目添加到 ListBox(或 CheckedListBox)控件

Posted

技术标签:

【中文标题】如何检测是不是将项目添加到 ListBox(或 CheckedListBox)控件【英文标题】:How to detect if items are added to a ListBox (or CheckedListBox) control如何检测是否将项目添加到 ListBox(或 CheckedListBox)控件 【发布时间】:2010-10-13 22:43:03 【问题描述】:

这似乎是一个基本简单的问题。我有一个带有列表框的 WinForms 对话框。该控件不是通过数据绑定填充的,而是填充了对

的调用
listBox.Items.Add (obj);

这个调用可能是从不同的地方异步进行的,我想挂钩列表框并观察其数据成员的变化,以便我可以执行其他 UI 更改(例如启用或禁用与列表框基于列表中的项目数)。

不幸的是,除非我完全一无所知,否则似乎没有可以挂钩来检测这一点的事件或虚拟方法。我可以挂钩选择更改,并且(对于 CheckedListBox)我可以挂钩检查状态更改。但不适用于对基础数据收集的更改。

我知道这在 Win32 中是可能的(有一个窗口消息)。我错过了什么?


[西蒙编辑]

解决方案

我被指出了正确的解决方案(我已将其标记为已接受的答案),即覆盖 ListBox 的 WndProc 方法并手动处理列表框消息。这是我确定(并且有效)的解决方案。可以对其进行修改以在事件中提供更多详细信息,或者将消息拆分为单独的事件,但对于我的需要,这已经足够了。

using System;
using System.Windows.Forms;

public class CheckedListBoxEx : CheckedListBox

    public CheckedListBoxEx()  

    private const int LB_ADDSTRING = 0x180;
    private const int LB_INSERTSTRING = 0x181;
    private const int LB_DELETESTRING = 0x182;
    private const int LB_RESETCONTENT = 0x184;

    protected override void WndProc(ref Message m)
    
        if (m.Msg == LB_ADDSTRING ||
            m.Msg == LB_INSERTSTRING ||
            m.Msg == LB_DELETESTRING ||
            m.Msg == LB_RESETCONTENT)
        
            ItemsChanged(this, EventArgs.Empty);
        
        base.WndProc(ref m);
    

    public event EventHandler ItemsChanged = delegate  ;

【问题讨论】:

@JohanPaul 链接已损坏 谢谢。我删除了链接,因为我不知道今天应该链接到哪里。 【参考方案1】:

我不知道您可以观看任何事件来显示项目已添加到列表框中。也许您可以改用您描述的 Win32 方法(即抓住一个句柄,使用 WndProc 等)。

或者,也许您可​​以使用另一个添加项目的类。例如,您可以让用户操作在新类中调用 Add 方法,而不是直接调用 ListBox 上的 Add 方法,然后将项目添加到 ListBox。您可以在该类中设置一个事件,让您可以查看添加的内容。

我也喜欢另一张海报提到的将 ListBox 子类化的想法......

【讨论】:

我忘记了能够覆盖 WndProc 方法。这巧妙地解决了我的问题。我可以创建一个自定义 ListBoxEx 类,重写此虚拟方法以获取新行为,但仍将其作为 ListBox 传递。这正是我想要的。谢谢!【参考方案2】:

这是另一个论坛上的帖子,建议创建一个包含该行为的子类。

http://www.eggheadcafe.com/forumarchives/netframeworkcompactframework/jul2005/post23265940.asp

【讨论】:

这很危险,因为这会暴露两个添加(其中第二个是有经验的开发者默认的)。此外,多态引用(对基类)不包括自定义 add 方法。 (1) listBox.Add(obj) (2) listBox.Items.Add(obj) 我已经考虑过(甚至原型化了)这个想法,但我试图保持在现有框架类型的范围内。现有的遗留代码只知道 System.Windows.Forms.ListBox 而不是任何特定的子类。在这种情况下,框架完全没有提供覆盖的钩子 嗯,我想我没有建议了 :) 链接已断开。【参考方案3】:

这个解决方案似乎有效 - 在我的情况下,我在 VB 中实现了它。我刚刚创建了一个继承列表框控件、实现 INotifyPropertyChanged 并隐藏 Items 属性的 ExtendedListbox 类。

Imports System.ComponentModel

Public Class ExtendedListBox:Inherits ListBox:Implements INotifyPropertyChanged

    Public Shadows Property Items() As ObjectCollection
        Get
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Items"))
            Return MyBase.Items
        End Get
        Set(value As ObjectCollection)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Items"))
            MyBase.Items.Clear()
            For Each o As Object In value
                MyBase.Items.Add(o)
            Next
        End Set
    End Property

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class

【讨论】:

当然,每次访问 Items 集合时都会触发。就我而言,没关系,但我知道这可能并不理想。【参考方案4】:

不幸的是,没有简单的方法可以使用继承或事件来做到这一点。您应该能够覆盖 Items 类的 Add 方法,但您无法使用它!您可能能够拦截消息循环以找出发生这种情况的时间,但这超出了我的经验。

我从您的问题中注意到的一件事是您提到项目是异步添加的。不要那样做。如果您在表单的线程上同步,您的问题可能会得到解决(如果您的问题是控件没有更新)。

【讨论】:

以上是关于如何检测是不是将项目添加到 ListBox(或 CheckedListBox)控件的主要内容,如果未能解决你的问题,请参考以下文章

如何将项目添加到 ListBox 中列表的开头?

C#将所选项目从ListBox1添加到ListBox2,相反[关闭]

将 ListBox 项保存到文件

在matlab的GUI中的listbox如何添加选项

从 tkinter.Listbox 中提取项目列表

向 ListBox 添加许多项目,同时保持 UI 响应