Member 11859517 Ответов: 1

Page up / page down – выберите пункт на предыдущей / следующей странице WPF C# listbox)


Привет
У меня есть ListView внутри Scrollviwer в wpf, Listbox caontain много элементов. Я хочу прокручивать список страница за страницей по щелчку клавиши page up/ page down.

Что я уже пробовал:

<pre>if (e.Key == Key.PageDown && selector.SelectedIndex == -1)
            {
                itemToSelect = selector.ItemContainerGenerator.ContainerFromIndex(0) as ListViewItem;
              
            }

его прокрутка, но не выбор следующего элемента страницы.

Как это сделать?

Graeme_Grant

Вам нужно выяснить последний видимый элемент ListBoxItem, сколько элементов ListBoxItem видны, затем найти следующий последний элемент ListBoxItem и вызвать scrollintoview на нем. То, как вы его кодируете, зависит от того, является ли это проект MVVM или нет.

Member 11859517

Graeme_Grant спасибо за ответ
нет, это не проект mvvm.
как я могу найти последний видимый ListboxItem, может быть, у вас есть ссылочный код.

Graeme_Grant

В соответствии с описанными выше шагами. Ключ состоит в том, чтобы проверить ListBoxItem Свойство IsVisible (Система.Окна)[^].

Member 11859517

извините, что это ListView, а не Listbox.

Graeme_Grant

На самом деле я не уверен, что вы читали то, что я написал, или смотрели на ссылку, которую я предоставил. IsVisible работает для элементов как в ListBox, так и в ListView. А вы пробовали? Если вы это сделали, то обновите свой вопрос кодом и опишите, где вы застряли.

У меня есть лучшая идея для простого решения - см. ниже.

Graeme_Grant

Вам нужно исправить свой вопрос.

1 Ответов

Рейтинг:
2

Graeme_Grant

Вот простое решение без MVVM, которое будет работать с VirtualizingStackPanel- протестировано со 100 000 элементами. Мы работаем непосредственно с ScrollViewer ListView. Будет работать даже при изменении размера списка.

1. Xaml

<Window

    x:Class="PagingVirtualListView.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"



    Title="Paging Virtualized ListView"

    Height="300" Width="500" WindowStartupLocation="CenterScreen">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <ListView x:Name="PeopleList" ItemsSource="{Binding Persons}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Avatar" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding AvatarUrl}" Margin="10" />
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Header="Name" Width="200" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Age" Width="50" DisplayMemberBinding="{Binding Age}" />
                </GridView>
            </ListView.View>
        </ListView>

        <StackPanel Grid.Column="1" Margin="10" VerticalAlignment="Center">
            <Button Content="PGUP" Click="OnPgUpClick" Padding="10 5" Margin="10"/>
            <Button Content="PGDn" Click="OnPgDnClick" Padding="10 5" Margin="10"/>
        </StackPanel>
    </Grid>

</Window>

2. Код-позади:
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        PeopleList.Loaded += PeopleList_Loaded;

        DataContext = this;
        Mock();
    }

    ScrollViewer lvScrollViewer;

    public ObservableCollection<Person> Persons { get; set; }
        = new ObservableCollection<Person>();

    private Random rand = new Random();

    private void Mock()
    {
        for (int i = 0; i < 100000; i++)
        {
            Persons.Add(new Person
            {
                AvatarUrl = "http://www.freepngimg.com/download/happy_person/2-2-happy-person-free-download-png.png",
                Name = $"Person {i}",
                Age = rand.Next(20, 60)
            });
        }
    }

    private void PeopleList_Loaded(object sender, RoutedEventArgs e)
    {
        PeopleList.Loaded -= PeopleList_Loaded;

        // remember the ListView's Scrollviewer
        lvScrollViewer = PeopleList.GetVisualChild<ScrollViewer>();
    }

    private void OnPgUpClick(object sender, RoutedEventArgs e)
    {
        lvScrollViewer.ScrollToVerticalOffset(
            Math.Max(0, lvScrollViewer.VerticalOffset - lvScrollViewer.ViewportHeight));
    }
    private void OnPgDnClick(object sender, RoutedEventArgs e)
    {
        lvScrollViewer.ScrollToVerticalOffset(
            Math.Min(lvScrollViewer.VerticalOffset + lvScrollViewer.ViewportHeight, Persons.Count - 1));
    }
}

public static class HelperExtension
{
    public static T GetVisualChild<T>(this Visual referenceVisual) where T : Visual
    {
        Visual child = null;
        for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
        {
            child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
            if (child != null && (child.GetType() == typeof(T)))
                break;
            else if (child != null)
            {
                child = GetVisualChild<T>(child);
                if (child != null && (child.GetType() == typeof(T)))
                    break;
            }
        }
        return child as T;
    }
}

public class Person
{
    public string AvatarUrl { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Наслаждаться.


Member 11859517

Спасибо Graeme_Grant за вашу большую помощь.
его прокрутка страница за страницей, без сомнения, но мне нужно выбрать 1-й пункт 2-й страницы или последний пункт 1-й страницы. ты меня понял?

Graeme_Grant

Приведенный выше код делает то, что вы задали в своем вопросе.

Однако для новых требований самая трудная часть (изменение видового экрана) делается выше для вас.

Для новых требований эта часть довольно прямолинейна. Вы можете установить свой размер страницы вручную или использовать размер lvScrollViewer.ViewportHeight (видимая область) для вычисления количества страниц и первого элемента каждой страницы и передачи этого значения в lvScrollViewer.ScrollToVerticalOffset метод.

Но моя рекомендация-не делайте этого, это дезориентирует пользователя, и он пропустит важные данные. Нынешним методом они этого не сделают.

Правильный метод подкачки данных состоит только в том, чтобы заполнить ListView страницей и иметь панель навигации внизу с кнопками навигации вперед/назад и номер страницы.

Member 11859517

Спасибо,
тем не менее я не могу выбрать элемент, как я могу найти индекс на основе вертикального ofset или ViewportHeight
.

Graeme_Grant

Это совершенно другая проблема для нового вопроса. Вам нужно использовать ListView.SelectedItem property и нет lvScrollViewer.ScrollToVerticalOffset Один устанавливает выделение, другой изменяет видимые элементы.