Как определить, добавлены ли элементы в элемент управления ListBox (или CheckedListBox) - PullRequest
21 голосов
/ 17 марта 2009

Это кажется принципиально простым вопросом. У меня есть диалоговое окно WinForms со списком. Этот элемент управления не заполнен привязкой данных, но заполнен вызовами

listBox.Items.Add (obj);

Возможно, что этот вызов может быть выполнен асинхронно из разных мест, и я хотел бы подключить список и наблюдать за изменениями в его элементах данных, чтобы я мог выполнять другие изменения пользовательского интерфейса (например, включать или отключать элементы управления, которые взаимодействуют с список на основе количества элементов в списке).

К сожалению, если я не полностью ничего не понимаю, кажется, что нет события или виртуального метода, который можно подключить, чтобы обнаружить это. Я могу подключиться для выбора изменений и (для CheckedListBox) я могу подключиться для изменений состояния проверки. Но не для изменений в базовом сборе данных.

Я знаю, что это возможно в Win32 (для этого есть сообщение в окне). Чего мне не хватает?


[Под редакцией Саймона]

Решение

Мне указали на правильное решение (которое я пометил как принятый ответ), которое заключается в переопределении метода WndProc в ListBox и обработке сообщений списка вручную. Вот решение, на котором я остановился (и работает). Его можно изменить, чтобы предоставить более подробную информацию о событии, или разбить сообщения на отдельные события, но для моих нужд этого достаточно.

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

Ответы [ 4 ]

7 голосов
/ 17 марта 2009

Я не знаю ни одного события, которое вы можете посмотреть, чтобы показать, что элемент был добавлен в ListBox. Возможно, вы можете использовать метод Win32, который вы описали вместо этого (то есть захватить дескриптор, использовать WndProc и т. Д.).

С другой стороны, возможно, вы можете использовать другой класс, который добавляет предметы вместо. Например, вместо непосредственного вызова метода Add в ListBox пользовательские действия могут вызвать метод Add внутри нового класса, который затем добавляет элемент в ListBox. Вы можете установить событие внутри этого класса, которое позволит вам наблюдать за тем, что было добавлено.

Мне также нравится идея создания подкласса ListBox, как упомянуто другим автором ....

3 голосов
/ 17 марта 2009

Вот сообщение на другом форуме, в котором рекомендуется создать дочерний класс с таким поведением.

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

1 голос
/ 31 января 2015

Это решение, похоже, работает - в моей ситуации я реализовал его в VB. Я только что создал класс ExtendedListbox, который наследует элемент управления listbox, реализует 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
0 голосов
/ 17 марта 2009

К сожалению, нет простого способа сделать это, используя наследование или события. Вы должны иметь возможность переопределить метод Add класса Items, но вы не можете получить к нему доступ! Возможно, вам удастся перехватить цикл сообщений, чтобы выяснить, когда это происходит, но это за пределами моего опыта.

Из вашего вопроса я заметил одну вещь: вы упоминаете, что элементы добавляются асинхронно. Не делай этого. Ваша проблема может быть решена, если вы выполняете синхронизацию в потоке формы (если ваша проблема в том, что элемент управления не обновляется).

...