Gleicher Zeilen-Inhalt nach Sortieren beim DataGridView
Frank Dzaebel, erstellt am: 11.2.2006, zuletzt geändert:
1.6.2008
Kategorie: DataGridView, .NET-Version: 2.0
Das DataGridView setzt die Binding-Position nach einem Klick auf den ColumnHeader unter .NET 1.1/2.0 nicht um, wenn das DataGridView etwa an
DataTable gebunden ist (gebundenes Szenario). In ungebundenen Szenarien funktioniert
bereits ein einfaches Setzen von
FirstDisplayedScrollingRowIndex auf den RowIndex
der gewünschten Zelle. Das bedeutet, dass der Inhalt der aktuellen Position nach dem (Sortier-) Klick anders ist. Um den gleichen Inhalt zu ermöglichen ist folgender Beispiel-Code eine Variante:
DataRow curRow;
CurrencyManager cm;
private void Form1_Load(object sender,EventArgs e)
{
this.adresseTableAdapter.Fill(this.frankDataSet.Adresse); //Beispiel
cm = (CurrencyManager)BindingContext[dataGridView1.DataSource,dataGridView1.DataMember];
curRow = ((DataRowView)cm.List[cm.Position]).Row;
cm.PositionChanged += new EventHandler(cm_PositionChanged);
dataGridView1.MouseUp += new MouseEventHandler(dataGridView1_MouseUp);
}
void cm_PositionChanged(object sender,EventArgs e)
{ curRow = ((DataRowView)cm.List[cm.Position]).Row;
}
void dataGridView1_MouseUp(object sender,MouseEventArgs e)
{
if (dataGridView1.HitTest(e.X,e.Y).Type != DataGridViewHitTestType.ColumnHeader) return;
DataRow dr; if (curRow == null) return;
object[] curArr = curRow.ItemArray;
for (int i = 0; i < cm.List.Count; i++)
{
dr = ((DataRowView)cm.List[i]).Row;
bool equals = true;
for (int j = 0; j < curArr.Length; j++)
if (curArr[j].ToString() != dr[j].ToString())
{equals = false; break;}
if (equals) { cm.Position = i; dataGridView1.Rows[i].Selected = true; break; }
}
}
Bei Primärschlüssel-Existenz performanter und sauberer:
Der oben angegebene Weg funktioniert auch, wenn der DataTable keinen primären Schlüssel
hat, weil er brute force alle Werte einer Spalte gegeneinander vergleicht,
um die Identität der Zeile herauszufinden.
Wenn es aber Zeilen gäbe, die vom Wert
her komplett gleich wären, könnten ggf. Positionierungsfehler auftreten und das
Verfahren kann bei grossen Datenmengen zu langsam sein.
Deswegen - wenn es einen Primärschlüssel in der Tabelle "Adresse"
gibt, kann folgendes performanter und sauberer sein:
DataRow curRow;
CurrencyManager cm;
string pkSpaltenName;
private void Form1_Load(object sender,EventArgs e)
{
this.adresseTableAdapter.Fill(this.frankDataSet.Adresse); //Beispiel
pkSpaltenName = frankDataSet.Adresse.PrimaryKey[0].ColumnName;
cm = (CurrencyManager)BindingContext[dataGridView1.DataSource,dataGridView1.DataMember];
curRow = ((DataRowView)cm.List[cm.Position]).Row;
cm.PositionChanged += new EventHandler(cm_PositionChanged);
dataGridView1.MouseUp += new MouseEventHandler(dataGridView1_MouseUp);
}
void cm_PositionChanged(object sender,EventArgs e)
{ curRow = ((DataRowView)cm.List[cm.Position]).Row;
}
void dataGridView1_MouseUp(object sender, MouseEventArgs e)
{
if (dataGridView1.HitTest(e.X, e.Y).Type != DataGridViewHitTestType.ColumnHeader) return;
if (curRow == null) return;
int positionID = adresseBindingSource.Find(pkSpaltenName, curRow[pkSpaltenName]);
adresseBindingSource.Position = positionID;
if (!dataGridView1.Rows[positionID].Displayed)
dataGridView1.FirstDisplayedScrollingRowIndex = positionID;
}
Im ungebundenen Szenario ggf. einfach:
DataGridView dgv = new DataGridView();
private void Form1_Load(object sender, EventArgs e)
{
Controls.Add(dgv);
dgv.Dock = DockStyle.Fill;
dgv.Columns.Add("Spalte1", "Spalte1");
dgv.Columns.Add("Spalte2", "Spalte2");
for (int i = 0; i < 200; i++)
dgv.Rows.Add("Wert" + i.ToString() + " 0",
"Wert" + i.ToString() + " 1");
dgv.Sorted += new EventHandler(dgv_Sorted);
}
void dgv_Sorted(object sender, EventArgs e)
{
dgv.FirstDisplayedScrollingRowIndex = dgv.CurrentRow.Index;
}