Pergunta

Eu tenho uma visão de lista que eu estou preenchendo com 8 colunas de dados do usuário. O usuário tem a opção de ativar refrescante auto, o que faz com que o ListView para ser apagada e repovoada com os dados mais recentes do banco de dados.

O problema é que quando os itens são apuradas e repovoada, a área visível salta para o topo da lista. Então, se eu estou olhando artigo 1000 do ano 2000, é muito inconveniente para voltar a esse item.

Basicamente, o que eu estou pedindo é, como faço para obter as distâncias de deslocamento atuais (X e Y) e, em seguida, restaurá-los?

Foi útil?

Solução

Eu tive o mesmo problema com um tempo atrás e acabei implementação de um algoritmo para comparar o modelo com a lista, então eu só acrescentou elementos / removidas que tinha mudado. Dessa forma, se não houve mudanças maciças da lista não saltar para o início. E a principal coisa que eu queria alcançar era a eficiência (para que a lista não pisca).

Outras dicas

Eu só queria fornecer algumas informações para aqueles que tentam desesperadamente usar a propriedade ListView.TopItem Buggy:

  1. Você deve definir a propriedade TopItem Depois de chamar ListView.EndUpdate
  2. Os itens do controle ListView deve ter sua propriedade Texto definido como algo diferente que String.Empty, ou a propriedade não irá funcionar.
  3. Definir a ListView.TopItem gera exceções referência nula intermitentemente. Sempre mantenha esta linha de código dentro de um bloco try ... catch.

Claro, isso fará com que a barra de rolagem do ListView para saltar a 0 e volta para o local do primeiro item, que é irritante. Por favor, atualize esta pergunta se você encontrar uma solução para este problema.

Eu usei o seguinte com êxito:

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)
{ }

A propriedade TopItemIndex em ListView é o que você está procurando, no entanto, ele tem alguns bugs confirmados que deveriam ter sido abordadas no VS2010 liberação .. não tenho certeza (não verificado).

De qualquer forma, a minha solução para fazer este trabalho é fazer isso:

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

Por alguma razão defini-lo diretamente não atualizá-lo, mas defini-lo como o último item e, em seguida, o que eu quero funciona de forma confiável para mim.

Olhe para a propriedade ListView.TopItem. Tem um índice, que deve conter a sua posição na lista. Encontrar esse índice na nova lista, e conjunto TopItem a esse item, e ele deve fazer o desdobramento automaticamente.

Infelizmente, você vai precisar usar alguns de interoperabilidade para se deslocar para a posição exata na ListView. Use GetScrollInfo winapi função para obter a posição de rolagem existente e SendMessage para se deslocar para a posição.

Existem em um artigo sobre CodeProject chamado Scrolling a um grupo com um ListView que pode orientá-lo para a solução.

A minha solução para manter a posição de rolagem:

Form variável de nível:

private static int scrollSpot = 0;

Dentro listview de atualização (ou seja, Timer, botão) para armazenar o local atual:

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

método Dentro refreshTheForm para mostrar o local armazenado (colocar à final do método):

if (scrollSpot <= 1)
{
     listView1.Items[scrollSpot].Selected = true;
}
else
{
     listView1.Items[scrollSpot - 2].Selected = true;
}
listView1.TopItem = listView1.SelectedItems[0]; 

Eu estava tendo espécie do mesmo problema. Eu tenho um ListView que eu preencher a cada 1/2 seg e quando eu definir o TopItem a um ListItem cujo índice> itens visíveis, então a lista saltou entre o topItem e volta 2 pontos.

Assim, para corrigir o problema, eu definir o TopIterm após a chamada para 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];​

Em meus testes, você nem sequer precisa do TopItem, embora eu usei um int para salvar o item selecionado. Também TopItem lança uma exceção se você estiver usando View.Tile ou View.LargeIcon.

Este código não se move as barras de rolagem:

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

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

listView1.EndUpdate();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top