ListView, похоже, не поддерживает событие Scroll. Мне нужно вызывать функцию всякий раз, когда список прокручивается; как бы я это сделал?
Как прослушать прокрутку в ListView?
Ответы (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();
}
}
Кажется, лучший подход - это решение Брайана. Однако он реагирует только на события, генерируемые полосами прокрутки, но не на события средней кнопки мыши.
если вы измените условие:
if (m.Msg == WM_HSCROLL || m.Msg == WM_VSCROLL)
this.OnScroll();
by:
if (m.Msg == 0x000c2c9)
this.OnScroll();
теперь он отвечает на все события прокрутки в списке.
Вот решение, которое учитывает каждый из режимов отображения 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 мс, у меня работает нормально, но вам может потребоваться настроить его в соответствии с вашим приложением.
Надеюсь, это поможет.