Nicht blockierter Update auf eine DataGridView
-
18-09-2019 - |
Frage
Ich verstehe, wie Sie Delegierten verwenden, um Steuerelemente im Hauptsteuerungs -Thread zu aktualisieren, funktioniert wie ein Zauber. Mein Problem hier ist, wenn ich eine große hinzufüge DataSet
(Sagen Sie 2000 Artikel) zu einer Grenze DataGridView
, Es dauert 5-8 Sekunden, bis das Netz besiegt wird, und während dieser 5-8 Sekunden ist die gesamte GUI gesperrt. Wie kann ich das aktualisieren DataGridView
So dass es die Benutzeroberfläche nicht sperrt?
Um klar zu sein, das Problem ist nicht, dass ich eine langsame Abfrage in eine Datenbank mache und die Benutzeroberfläche blockiert, ich habe bereits das DataSet object[]
und Hinzufügen der Objektarray zu a BindingList<object>
was die DataGrid
ist an so gebunden:
BindingList<object> dataProvider = new BindingList<object>();
DataGridView gridView = new DataGridView();
gridView.DataSource = dataProvider;
// ...stuff happens...
object[] source = dataSet; //of 2000 items
foreach (object item in source) { //this foreach blocks
dataProvider.Add(item);
}
Ich habe verschiedene Dinge ausprobiert (von denen ich wusste dataProvider.Add()
, Aber das war egal, da es immer noch im Kontrollfaden passieren musste.
Ein paar gute Vorschläge drehten sich darum, das zu bauen BindingList
zuerst und dann das festlegen gridView.DataSource
. Während dies funktioniert (es aktualisiert das Netz sofort), besteht die einzige Möglichkeit, weitere Daten hinzuzufügen, darin, ein weiteres neues zu erstellen BindingList
, machen a gridView.DataSource.copyTo()
(Um die vorhandenen Daten zu erhalten) und fügen Sie die neuen Daten darüber hin gridView.DataSource
zum neuen BindingList
. Dies funktioniert für mich nicht, da die Objekte in meiner Liste nicht statisch sind, sie werden jeweils asynchron auf einen Server hochladen und sie auf einen neuen kopieren BindingList
würde Probleme verursachen.
Lösung
Sie fügen Datensätze hinzu, während die GridView mit der Datenquelle verknüpft ist. Dies bedeutet, dass das Layout jedes Mal aktualisiert wird.
Wie wäre es, wenn Sie zuerst Ihre DataSource füllen und erst dann die DataSource -Eigenschaft festlegen?
gridView.DataSource = null;
...stuff happens...
object[] source = dataSet; //of 2000 items
foreach (object item in source) { //this foreach blocks
dataProvider.Add(item);
}
gridView.DataSource = dataProvider;
Die Foreach -Loop könnte zu einem anderen Thread gehen, aber ich glaube nicht, dass Sie das brauchen werden.
Andere Tipps
Wie Nick sagte BackgroundWorker
ist wahrscheinlich die beste Wahl.
Hier ist ein sehr einfaches Beispiel
public partial class Form1 : Form
{
BackgroundWorker b = new BackgroundWorker();
public Form1()
{
InitializeComponent();
b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted);
b.DoWork += new DoWorkEventHandler(b_DoWork);
}
void b_DoWork(object sender, DoWorkEventArgs e)
{
// build dataset here and assigning it to results
e.Result = dataset;
}
void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// assign the dataset you built in DoWork in the gridview and update it
dataGridView1.DataSource = e.Result;
dataGridView1.Update();
}
private void button1_Click(object sender, EventArgs e)
{
b.RunWorkerAsync();
}
}
Schauen Sie sich an a Hintergrundbearbeiter. Ich weiß selbst nicht viel über sie, aber eine kleine Suche bei Google zeigt dies als gute Möglichkeit.