2011-09-30 35 views
5

Ho un .NET 3.5 WinForm che ha un controllo ListView con la vista impostata nella modalità Dettagli. Funziona come un elenco scorrevole di voci di stato su un'attività di background lunga. Ho il ListViewItem più recente (voce di stato) aggiunto in fondo. Per assicurare che sia visto, assicuro la visibilità del nuovo oggetto dopo l'aggiunta. Tutto funziona bene; la vista elenco scorre automaticamente verso il basso per mostrare l'elemento più recente.Controllo scorrimento ListView: scorrere verso il basso se l'utente non sta scorrendo?

private void AddListItem(DateTime timestamp, string message, int index) 
{ 
    var listItem = new ListViewItem(timestamp.ToString()); 
    listItem.SubItems.Add(message); 
    statusList.Items.Insert(index, listItem); 
    statusList.Items[statusList.Items.Count - 1].EnsureVisible(); 
} 

Il problema è se l'utente scorre fino a guardare i messaggi meno recenti, il ListView viene fatto scorrere verso il basso per rendere il nuovo elemento visibile come si entra in gioco. C'è un modo per controllare questo comportamento per verificare se l'utente sta interagendo con la barra di scorrimento (in particolare, se stanno tenendo premuto il pulsante del mouse sulla barra di scorrimento)? Probabilmente è anche accettabile rilevare se lo scroll è sempre in basso. se non è in fondo, allora non garantirei la visibilità dell'ultimo elemento. Qualcosa di simile:

private void AddListItem(DateTime timestamp, string message, int index) 
{ 
    var listItem = new ListViewItem(timestamp.ToString()); 
    listItem.SubItems.Add(message); 
    statusList.Items.Insert(index, listItem); 
    if (!statusList.IsScrollbarUserControlled) 
    { 
     statusList.Items[statusList.Items.Count - 1].EnsureVisible(); 
    } 
} 

Cosa c'è di strano è che quando l'utente sta tenendo giù la barra di scorrimento "manico" in atto, il manico non si muove (il che implica che la vista non è effettivamente scorrere verso il basso programatically), ma in infatti è.

Aggiornamento: È possibile rilevare la posizione della barra di scorrimento, ad esempio, se ci si trova in fondo o no?

risposta

2

Confronta, ad esempio, ProcMon di SysInternals. Aggiungi una casella con l'etichetta "Auto scroll" in modo che l'utente possa spegnerlo.

+0

Non so perché questo era -1'd. Anche se questo non risponde alla domanda, hai fornito un'alternativa molto ragionevole –

+0

@Stealth - alcuni scarponi per cavalli stanno sistematicamente ridiscutendo le mie risposte. Non ho idea del perché, non ti preoccupare. Grazie per il tuo voto. –

+0

Entrambe le risposte sembrano corrette, ma alla fine sto seguendo il tuo suggerimento perché penso che soddisfi le esigenze dell'utente e meno sorpreso su come funzionerà. Ho usato il monitor processore come suggerito e funziona bene per un'esperienza UX. –

4

Due passi per risolvere questo problema:

  1. Il WinForms ListView non dispone di un evento Scrolled. Dovremo definirne uno.
  2. Determinare quando il ListView è inattivo e chiamare GuaranteVisible solo quando è rimasto inattivo per un po '.

Per il primo problema, ereditano una nuova classe da ListView, la priorità sulle pompa messaggio di Windows, e sollevare un evento quando l'utente scorre IT:

public class MyListView : ListView 
{ 
    public event EventHandler<EventArgs> Scrolled; 

    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 

     const int wm_vscroll = 0x115; 
     if (m.Msg == wm_vscroll && Scrolled != null) 
     { 
      Scrolled(this, new EventArgs()); 
     } 
    } 
} 

ora sappiamo quando l'utente scorre la lista vista. Il tuo prossimo problema è determinare se la vista elenco è inattiva; cioè, se l'utente non lo ha fatto scorrere per un po '.

Ci sono diversi modi per farlo. A tale scopo, utilizzerò solo un timestamp per indicare l'ultimo tempo di scorrimento:

private DateTime lastScrollTime; 

... 

listView.Scrolled += delegate { lastScrollTime = DateTime.Now }; 

... 

private void AddListItem(DateTime timestamp, string message, int index) 
{ 
    var listItem = new ListViewItem(timestamp.ToString()); 
    listItem.SubItems.Add(message); 
    statusList.Items.Insert(index, listItem); 

    // Scroll down only if the list view is idle. 
    var idleTime = TimeSpan.FromSeconds(5); 
    var isListViewIdle = DateTime.Now.Subtract(this.lastScrollTime) > idleTime; 
    if (isListViewIdle) 
    { 
     statusList.Items[statusList.Items.Count - 1].EnsureVisible(); 
    } 
} 
+0

Quanto di un successo nelle prestazioni è questo? È qualcosa che hai usato in passato? –

+0

Non vedrai un successo in termini di prestazioni. –

+0

Sono curioso da dove proviene questa costante 0x115. –

Problemi correlati