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

发布于 2024-07-15 09:34:15 字数 1369 浏览 9 评论 0原文

这似乎是一个非常简单的问题。 我有一个带有列表框的 WinForms 对话框。 该控件通过数据绑定填充,但充满了对以下内容的调用:

listBox.Items.Add (obj);

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

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

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


[由 Simon 编辑]

解决方案

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

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

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).

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.

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


[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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

知足的幸福 2024-07-22 09:34:15

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

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

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

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.).

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.

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

时光是把杀猪刀 2024-07-22 09:34:15

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

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

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

半边脸i 2024-07-22 09:34:15

这个解决方案似乎有效 - 在我的情况下,我在 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

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.

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
旧时模样 2024-07-22 09:34:15

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

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

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.

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文