WinForms ListView, запоминание места прокрутки при перезагрузке - PullRequest
12 голосов
/ 09 марта 2009

У меня есть представление списка, которое я заполняю 8 столбцами пользовательских данных. У пользователя есть возможность включить автоматическое обновление, в результате чего ListView будет очищен и заполнен самыми последними данными из базы данных.

Проблема в том, что когда элементы очищаются и пополняются, видимая область возвращается к началу списка. Поэтому, если я смотрю на пункт 1000 2000 года, мне очень неудобно возвращаться к этому пункту.

По сути, я спрашиваю, как получить текущие расстояния прокрутки (x и y) и затем восстановить их?

Ответы [ 9 ]

15 голосов
/ 24 января 2010

Я просто хотел предоставить некоторую информацию для тех, кто отчаянно пытается использовать ошибочное свойство ListView.TopItem:

  1. Вы ДОЛЖНЫ установить свойство TopItem ПОСЛЕ вызова ListView.EndUpdate
  2. Элементы элемента управления ListView ДОЛЖНЫ иметь свойство Text, установленное на что-то другое чем String.Empty, иначе свойство не будет работать.
  3. Установка ListView.TopItem периодически выбрасывает исключения нулевой ссылки. Всегда держите эту строку кода внутри блока Try ... Catch.

Конечно, это заставит полосу прокрутки ListView перейти к 0 и вернуться к местоположению верхнего элемента, что раздражает. Пожалуйста, обновите этот вопрос, если найдете решение этой проблемы.

8 голосов
/ 11 октября 2012

Я успешно использовал следующее:

int topItemIndex = 0;
try
{
     topItemIndex = listView1.TopItem.Index;
}
catch (Exception ex)
{ }
listView1.BeginUpdate();
listView1.Items.Clear();
//CODE TO FILL LISTVIEW GOES HERE
listView1.EndUpdate();
try 
{ 
    listView1.TopItem = listView1.Items[topItemIndex];
}
catch (Exception ex)
{ }
4 голосов
/ 09 марта 2009

Недавно у меня была такая же проблема, и я в итоге реализовал алгоритм для сравнения модели со списком, поэтому я только добавил / удалил элементы, которые изменились. Таким образом, если не было массовых изменений, список не переходил к началу. И главное, чего я хотел добиться, - это эффективности (чтобы список не мигал).

3 голосов
/ 06 декабря 2011

Свойство TopItemIndex в ListView - это то, что вы ищете, однако в нем есть некоторые подтвержденные ошибки, которые должны были быть исправлены в выпуске VS2010 ... не уверен (не проверял).

В любом случае, мой обходной путь для выполнения этой работы заключается в следующем:

listViewOutput.TopItemIndex = outputList.Count - 1;
listViewOutput.TopItemIndex = myNewTopItemIndex;

По какой-то причине его установка напрямую не обновляет его, но установка последнего элемента, а затем того, который я хочу, надежно работает для меня.

1 голос
/ 09 марта 2009

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

0 голосов
/ 12 августа 2013

В моих тестах вам даже не понадобился TopItem, хотя я использовал int для сохранения выбранного элемента. Также TopItem генерирует исключение, если вы используете View.Tile или View.LargeIcon.

Этот код не перемещает полосы прокрутки:

listView1.BeginUpdate();
listView1.Items.Clear();

// loop through your add routine
listView1.Items.Add(lvi);

listView1.EndUpdate();
0 голосов
/ 10 ноября 2011

Мое решение для поддержания позиции прокрутки:

Переменная уровня формы:

private static int scrollSpot = 0;

Обновление внутри списка (т. Е. Таймер, кнопка) для сохранения текущего места:

scrollSpot = this.listView1.TopItem.Index;
refreshTheForm();

Внутри метода refreshTheForm для отображения сохраненного места (помещается в самом конце метода):

if (scrollSpot <= 1)
{
     listView1.Items[scrollSpot].Selected = true;
}
else
{
     listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0]; 
0 голосов
/ 25 марта 2010

У меня была такая же проблема. У меня есть listView, который я заполняю каждые полсекунды, и когда я устанавливаю TopItem на ListItem, индекс которого> видимые элементы, то список перемещается между topItem и двумя задними точками.

Итак, чтобы исправить проблему, я установил TopIterm ПОСЛЕ вызова EndUpdate.

lvB.EndUpdate();
lvI.EndUpdate();
lvR.EndUpdate();

if (lstEntryInts.Items.Count > 0)
    lstEntryInts.TopItem = lstEntryInts.Items[iTopVisIdx];
if (lstEntryBools.Items.Count > 0)
    lstEntryBools.TopItem = lstEntryBools.Items[iTopVisIdx];
if (lstEntryReals.Items.Count > 0)
    lstEntryReals.TopItem = lstEntryReals.Items[iTopVisIdx];​
0 голосов
/ 09 марта 2009

К сожалению, вам понадобится некоторое взаимодействие для прокрутки до точного положения в ListView. Используйте GetScrollInfo функцию winapi для получения существующей позиции прокрутки и SendMessage для прокрутки до позиции.

В статье о CodeProject под названием Прокрутка до группы с помощью ListView , которая может помочь вам найти решение.

...