2010-07-21 3 views
5

Ich habe den folgenden Code, der im Grunde Werte aus einer Datenbank nimmt und eine Listview auffüllt..NET Listview Refresh

using (IDataReader reader = cmd.ExecuteReader()) 
{      
    lvwMyList.Items.Clear(); 
    while (reader.Read()) 
    { 
     ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString()); 
     lvi.SubItems.Add(reader["Value2"].ToString());      
    } 
} 

Das Problem, das ich habe, ist, dass diese immer wieder in kurzen Abständen (jede Sekunde) und die Ergebnisse in den Elementen in der Listenansicht kontinuierlich ausgeführt wird, verschwinden und wieder erscheinen. Gibt es eine Möglichkeit, die Aktualisierung der Listenansicht zu stoppen, bis sie mit den Aktualisierungen fertig ist? So etwas wie unten:

using (IDataReader reader = cmd.ExecuteReader()) 
{      
    lvwMyList.Items.Freeze(); // Stop the listview updating 
    lvwMyList.Items.Clear(); 
    while (reader.Read()) 
    { 
     ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString()); 
     lvi.SubItems.Add(reader["Value2"].ToString());      
    } 
    lvwMyList.Items.UnFreeze(); // Refresh the listview 
} 
+0

Freeze bedeutet etwas anderes: es bedeutet, dass das Objekt (in diesem Fall eine Sammlung von Elementen) nicht ändert, während es eingefroren ist. In diesem Fall modifizierst du es sofort! –

+1

Freeze war nur ein Begriff, den ich verwendet habe, um meine Anforderung zu erklären –

Antwort

9

So:

try 
{ 
    lvwMyList.BeginUpdate(); 
    //bla bla bla 

} 
finally 
{ 
    lvwMyList.EndUpdate(); 
} 

Vergewissern Sie sich, dass Sie lvwMyList.Items.Clear()nachBeginUpdate aufrufen, wenn Sie die Liste löschen möchten, bevor es zu füllen.

+1

Es wird immer noch "blinken", wenn Sie die Elemente löschen. Gleiches passiert bei TreeView. – leppie

+1

Das macht definitiv das, wonach ich gefragt habe. Das einzige Problem ist, dass es auch das Formular praktisch sperrt :-) –

+1

Mit clear in Beginupdate sollte verhindert werden, dass es blinkt. Das Formular wird nicht von beginupdate gesperrt, sondern von Ihrem Code, der die neuen Elemente hinzufügt. Versuchen Sie, alle Elemente aus dem DB zu holen, bevor Sie das Update durchführen. – jgauffin

0

Sie können auch versuchen, die sichtbaren oder aktivierten Eigenschaften während des Updates auf false zu setzen und zu sehen, ob Ihnen diese Ergebnisse besser gefallen. Setzen Sie die Werte natürlich auf "true" zurück, wenn die Aktualisierung abgeschlossen ist.

Ein anderer Ansatz besteht darin, ein Panel zu erstellen, das die Listbox überlagert. Legen Sie die Eigenschaften left, right, height und width auf die gleiche Weise wie Ihre Listbox fest und legen Sie die Eigenschaft visible während der Aktualisierung auf true fest, false, nachdem Sie fertig sind.

+1

Das Deaktivieren und Aktivieren der Kontrolle scheint das Problem zu verschlimmern –

1

Dies ist mein erstes Mal auf StackOverflow, so entschuldigen Sie die unordentliche Code-Formatierung unten.

Um zu verhindern, dass das Formular beim Aktualisieren der ListView gesperrt wird, können Sie die unten stehende Methode verwenden, um dieses Problem zu beheben.

Hinweis: Diese Methode sollte nicht verwendet werden, wenn Sie das ListView mit mehr als etwa 20.000 Elementen füllen möchten. Wenn Sie dem ListView mehr als 20.000 Elemente hinzufügen möchten, sollten Sie das ListView im virtuellen Modus ausführen.

Sie müssen kein IProgress-Objekt angeben, verwenden Sie einfach null, und die Methode funktioniert genauso gut.

Im Folgenden finden Sie ein Beispiel für die Verwendung der Methode.

Definieren Sie zuerst eine Klasse, die die Daten für das ListViewItem enthält.

public class TestListViewItemClass 
{ 
    public int TestInt { get; set; } 

    public string TestString { get; set; } 

    public DateTime TestDateTime { get; set; } 

    public TimeSpan TestTimeSpan { get; set; } 

    public decimal TestDecimal { get; set; } 
} 

Erstellen Sie dann eine Methode, die Ihre Datenelemente zurückgibt. Diese Methode kann eine Datenbank abfragen, eine Web-Service-API aufrufen oder was auch immer, solange sie eine IEnumerable Ihres Klassentyps zurückgibt.

Schließlich können Sie in dem Formular, in dem sich Ihre ListView befindet, die ListView auffüllen. Zu Demonstrationszwecken verwende ich das Load-Ereignis des Formulars, um das ListView aufzufüllen. Mehr als wahrscheinlich, möchten Sie dies an anderer Stelle auf dem Formular tun.

Ich habe die Funktion, die ein ListViewItem aus einer Instanz meiner Klasse, TestListViewItemClass generiert. In einem Produktionsszenario möchten Sie die Funktion wahrscheinlich anderswo definieren.

private async void TestListViewForm_Load(object sender, EventArgs e) 
{  
    var function = new Func<TestListViewItemClass, ListViewItem>((TestListViewItemClass x) => 
    { 
     var item = new ListViewItem(); 

     if (x != null) 
     { 
      item.Text = x.TestString; 
      item.SubItems.Add(x.TestDecimal.ToString("F4")); 
      item.SubItems.Add(x.TestDateTime.ToString("G")); 
      item.SubItems.Add(x.TestTimeSpan.ToString()); 
      item.SubItems.Add(x.TestInt.ToString()); 
      item.Tag = x; 

      return item; 
     } 

     return null; 
    }); 

     PopulateListView<TestListViewItemClass>(this.listView1, function, GetItems(), progress); 

} 

Im obigen Beispiel, habe ich ein IProgress Objekt im Konstruktor des Formulars wie folgt aus:

progress = new Progress<int>(value => 
{ 
    toolStripProgressBar1.Visible = true; 

    if (value >= 100) 
    { 
     toolStripProgressBar1.Visible = false; 
     toolStripProgressBar1.Value = 0; 
    } 
    else if (value > 0) 
    { 
     toolStripProgressBar1.Value = value; 
    } 
}); 

ich oft in Projekten dieser Methode zu bevölkern ein Listview verwendet haben, wo wir oben waren bevöl bis zu 12.000 Elemente in der ListView, und es ist extrem schnell. Die Hauptsache ist, dass Sie Ihr Objekt vollständig aus der Datenbank erstellen lassen müssen, bevor Sie das ListView für Aktualisierungen berühren.

Hoffentlich ist das hilfreich.

Ich habe unten eine asynchrone Version der Methode eingefügt, die die Hauptmethode aufruft, die oben in diesem Beitrag gezeigt wird.

public static Task PopulateListViewAsync<T>(ListView listView, Func<T, ListViewItem> func, 
     IEnumerable<T> objects, IProgress<int> progress) where T : class, new() 
{ 
    return Task.Run(() => PopulateListView<T>(listView, func, objects, progress)); 
}