Подтвердить что ты не робот

Как определить, добавлены ли элементы в элемент управления ListBox (или CheckedListBox)

Это похоже на принципиально простой вопрос. У меня есть диалоговое окно 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 { };
}
4b9b3361

Ответ 1

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

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

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

Ответ 3

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

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

Ответ 4

Это решение, похоже, работает - в моей ситуации я реализовал его в 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