"Бесконечная прокрутка" в ListView / избегание событий прокрутки повторного участника


Моя цель-имитировать "бесконечную прокрутку" в WPF ListView. Я достиг этой цели с помощью некоторых далеко не идеальных методов, и я уверен, что есть лучший способ сделать это.

Под "бесконечной прокруткой" я подразумеваю следующее:
Предположим, что a ListView имеет 20 элементов (упорядоченных 1, 2, 3, 4, ... 17, 18, 19, 20). Когда пользователь прокручивает вниз один элемент, элемент в верхней части ListView удаляется и помещается в конце ListView, поэтому порядок элементов равен 2, 3, 4, 5, ... 18, 19, 20, 1. Теперь, если пользователь прокручивает два пункта вниз, два верхних элементы удаляются и помещаются в конце таким образом, чтобы порядок элементов был 4, 5, 6, 7, ... 20, 1, 2, 3. Теперь аналогично, если пользователь прокручивает один элемент вверх, элемент в нижней части ListView удаляется и помещается в начало, так что порядок элементов равен 3, 4, 5, 6, ... 19, 20, 1, 2.

Я достиг этой задачи со следующей функцией, назначенной событию ScrollChanged из ScrollViewer, которое я хочу быть "бесконечным":

// sv - the ScrollViewer to which this event handler is listening
// lv - the ListView associated with "sv"
bool handle_scroll = true;
private void inf_scroll(object sender, ScrollChangedEventArgs e) {
    if (handle_scroll) {
        for (int i = 0; i < e.VerticalChange; i++) {
            object tmp = lv.Items[0];
            lv.Items.RemoveAt(0);
            lv.Items.Add(tmp);
            handle_scroll = false;
        }
        for (int i = 0; i > e.VerticalChange; i--) {
            object tmp = lv.Items[lv.Items.Count - 1];
            lv.Items.RemoveAt(lv.Items.Count - 1);
            lv.Items.Insert(0, tmp);
            handle_scroll = false;
        }
        if(!handle_scroll){
            sv.ScrollToVerticalOffset(sv.VerticalOffset - e.VerticalChange);
        }
    }
    else {
        handle_scroll = true;
    }
}

Обратите внимание на переменную handle_scroll. Я поставил это на место, потому что вызов sv.ScrollToVerticalOffset вызовет весь inf_scroll функция, вызываемая рекурсивно, если ее там не было.

Я знаю , что прокручивать ScrollViewer в обработчике событий ScrollChanged - плохая практика, поэтому я спрашиваю: есть ли лучший способ сделать это? Как я могу предотвратить рекурсивные вызовы inf_scroll? Есть ли лучший способ имитировать "бесконечную прокрутку"?

1 7

1 ответ:

Хотя он явно не избегает прокрутки в обработчике ScrollChanged, Вы можете попробовать следующее:

// sv - the ScrollViewer to which this event handler is listening
// lv - the ListView associated with "sv"
private void inf_scroll(object sender, ScrollChangedEventArgs e) {
    for (int i = 0; i < e.VerticalChange; i++) {
        object tmp = lv.Items[0];
        lv.Items.RemoveAt(0);
        lv.Items.Add(tmp);
    }
    for (int i = 0; i > e.VerticalChange; i--) {
        object tmp = lv.Items[lv.Items.Count - 1];
        lv.Items.RemoveAt(lv.Items.Count - 1);
        lv.Items.Insert(0, tmp);
    }
    lv.ScrollChanged -= inf_scroll;        // remove the handler temporarily
    sv.ScrollToVerticalOffset(sv.VerticalOffset - e.VerticalChange);
    Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(() =>{
        sv.ScrollChanged += inf_scroll;    // add the handler back after the scrolling has occurred to avoid recursive scrolling
    }));
}