C# 如何检测项目是否添加到 ListBox(或 CheckedListBox)控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/655956/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:05:58  来源:igfitidea点击:

How to detect if items are added to a ListBox (or CheckedListBox) control

c#.netwinformslistboxcheckedlistbox

提问by Simon Gillbee

This seems like a fundamentally simple question. I have a WinForms dialog box with a listbox. This control is notpopulated via data-binding but is filled with calls to

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

listBox.Items.Add (obj);

It is possible that this call can be made asynchronously from various places and I would like to hook the listbox and watch for changes in its data members so that I can perform other UI changes (such as enable or disable controls which interact with the listbox based on the number of items in the list).

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

Unfortunately, unless I'm being completely clueless, there does not seem to be an event or virtual method which can be hooked to detect this. I can hook for select changes and (for CheckedListBox) I can hook for check-state changes. But not for changes to the underlying data collection.

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

I know this is possible in Win32 (there is a window message for this). What am I missing?

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



[Edited by Simon]

[西蒙编辑]

Solution

解决方案

I was pointed to the correct solution (which I have marked as the accepted answer) which is to override the WndProc method of the ListBox and handle the listbox messages manually. Here is the solution that I settled on (and works). It could be modified to provide more details in the event, or split the messages into separate events, but for my needs this is sufficient.

有人指出了正确的解决方案(我已将其标记为接受的答案),即覆盖 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 { };
}

采纳答案by Michael Todd

I don't know of any event that you can watch to show that an item has been added to a ListBox. Perhaps you can use the Win32 method you described instead (i.e. grab a handle, use WndProc, etc.).

我不知道您可以观看任何事件以显示某个项目已添加到 ListBox。也许您可以改用您描述的 Win32 方法(即抓取句柄、使用 WndProc 等)。

Alternately, perhaps you can use another class that adds items instead. For example, rather than calling the Add method on the ListBox directly, you could have user-actions call the Add method inside the new class which then adds the item to the ListBox. You could set an event inside that class that would allow you to watch what's been added.

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

I also like the idea of subclassing the ListBox as mentioned by another poster....

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

回答by Kevin Laity

Here's a post on another forum that recommends creating a child class that includes that behaviour.

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

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

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

回答by Michael Meadows

Unfortunately, there's no easy way to do this using inheritance or events. You should be able to override the Add method of the Items class, but you can't get to it! You may be able to intercept the message loop to figure out when this is happening, but that's beyond my experience.

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

One thing I noticed from your question is that you mention items are being added asynchronously. Don't do that. Your problem may be solved if you synchronize on the form's thread (if your problem is that the control isn't updating).

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

回答by RLB

This solution seems to work - in my situation, I implemented it in VB. I just created an ExtendedListbox class which inherits the listbox control, implements INotifyPropertyChanged and shadows the Items Property.

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

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