在ListView中的“无限滚动”/避免可重入的滚动事件

7
我的目标是在WPF ListView中模拟“无限滚动”。我已经用一些不太理想的方法完成了这个任务,我相信有更好的方法来实现它。
所谓“无限滚动”,是指以下情况: 假设一个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。同样地,如果用户向上滚动一个项目,则移除底部的项目并将其放置在开头,因此项目的顺序为3, 4, 5, 6, ... 19, 20, 1, 2
我通过将以下函数分配给我希望成为“无限”的ScrollViewerScrollChanged事件来完成此任务:
// 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函数被递归调用。
我知道在ScrollChanged事件处理程序中滚动ScrollViewer是不好的做法,所以我想问:有更好的方法吗?如何防止对inf_scroll的递归调用?有更好的模拟“无限滚动”的方法吗?

如果用户向上滚动会怎么样?它会移除最后一项并添加到开头还是不修改列表? - Magnetron
@Magnetron 向上滚动应该删除最后一项并将其添加到开头。我编辑了问题以澄清。 - Den Dinh
1个回答

3

虽然在 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
    }));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接