Как прослушать прокрутку в ListView?

ListView, похоже, не поддерживает событие Scroll. Мне нужно вызывать функцию всякий раз, когда список прокручивается; как бы я это сделал?


person Simon    schedule 16.12.2008    source источник


Ответы (3)


Зачем нужно вызывать функцию при прокрутке списка?

Если вы меняете элементы по мере их прокрутки, я бы рекомендовал установить виртуальный список.

Или вы можете переопределить список и сделать это:

public class TestListView : System.Windows.Forms.ListView
{
    private const int WM_HSCROLL = 0x114;
    private const int WM_VSCROLL = 0x115;
    public event EventHandler Scroll;

    protected void OnScroll()
    {

        if (this.Scroll != null)
            this.Scroll(this, EventArgs.Empty);

    }

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
            this.OnScroll();
    }
}
person Brian Rudolph    schedule 17.12.2008

Кажется, лучший подход - это решение Брайана. Однако он реагирует только на события, генерируемые полосами прокрутки, но не на события средней кнопки мыши.

если вы измените условие:

   if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL) 
             this.OnScroll();

by:

   if (m.Msg == 0x000c2c9) 
             this.OnScroll();

теперь он отвечает на все события прокрутки в списке.

person keimacias    schedule 05.08.2010

Вот решение, которое учитывает каждый из режимов отображения ListView:

Мы полагаемся на то, что при прокрутке ListView положение элементов меняется. Если мы проверим изменение свойства Bounds первого ListViewItem, мы сможем отследить, произошло ли перемещение.

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

private Rectangle _firstItemBounds = null;

При заполнении ListView установите для этой переменной значение Bounds первого элемента. Например:

private void Form1_Load(object sender, EventArgs e)
{
    for (int i = 0; i < 1000; i++)
    {
        listView1.Items.Add(new ListViewItem("Item " + i));
    }

    _firstItemBounds = listView1.Items[0].Bounds;
}

Затем добавьте обработчик события Tick Timer:

private void timer1_Tick(object sender, EventArgs e)
{
    if (listView1.Items[0] == null)
    {
        return;
    }

    Rectangle bounds = listView1.Items[0].Bounds;

    if (bounds != _firstItemBounds)
    {
        _firstItemBounds = bounds;

        // Any scroll logic here
        // ...
    }
}

Значение по умолчанию Timer Interval, равное 100 мс, у меня работает нормально, но вам может потребоваться настроить его в соответствии с вашим приложением.

Надеюсь, это поможет.

person Dave R.    schedule 17.12.2008