Benutzer mit den meisten Antworten
GridView wird nicht korrekt ausgelsen

Frage
-
Hallo,
ich habe in meiner WinForms Applikation folgende GridView erstellt, in die Dateiinhalte eingelesen werden:
Veränderte Inhalte der GridView sollen zunächst in eine List<string> eingelesen werden. Folgender Algorithmus macht das auch, allerdings nur die ersten beiden Zeilen. Die letzte Zeile wird immer so übernommen, wie sie bereits dasteht. Erst, wenn ich innerhalb der GridView auf eine beliebige leere Zelle der letzten Zeile geklickt habe, werden alle Inhalte in die List verfrachtet. Woran liegt das?
int zeilenAnzahl = DataGridView_CSVContent.Rows.Count - 1, spaltenAnzahl; . . for (int reihe = 0; reihe < zeilenAnzahl; reihe++) { spaltenAnzahl = DataGridView_CSVContent.Rows[reihe].Cells.Count; try { for (int spalte = 0; spalte < spaltenAnzahl; spalte++) { splitList.Add(DataGridView_CSVContent.Rows[reihe].Cells[spalte].Value.ToString()); } } catch (NullReferenceException) { message = " Die GridView hat einen invaliden Aufbau! Sie dürfen die Struktur nicht verändern. Haben sie vielleicht Zellinhalte gelöscht?"; this.Ausgabe(message, "Error", MessageBoxIcon.Error); return; } } . .
- Bearbeitet tklustig Freitag, 19. April 2019 11:39
Antworten
-
Hi Thomas,
nachfolgend eine kleine Demo (ohne Designer, einfach in eine leere Form kopieren). Mit dem obersten Button wird eine CVS-Datei (Semikolon-separiert) geladen und im DataGridView angezeigt, dann können die Zellen geändert werden, mit dem zweiten Button können die aktuellen Daten wieder in einer CSV-Datei abgelegt werden.Wenn Du da noch die Befehle zur Fehlerprotokollierung hinzufügst, dann leibt das Programm doch bedeutend kürzer.
using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Load += new System.EventHandler(this.Form02_Load); } // Arbeit ohne Designer in einer leeren Form private Button btnLoad = new Button() { Text = "Laden", Dock = DockStyle.Top }; private Button btnSave = new Button() { Text = "Speichern", Dock = DockStyle.Top }; private DataGridView dgv = new DataGridView() { Dock = DockStyle.Top }; private string fileNameInput = @"Form03Demo.csv"; private string fileNameOutput = @"Form03Demo_neu.csv"; private List<Data> daten = new List<Data>(); private void Form02_Load(object sender, EventArgs e) { this.Controls.AddRange(new Control[] { dgv, btnSave, btnLoad }); btnLoad.Click += BtnLoad_Click; btnSave.Click += BtnSave_Click; } private void BtnLoad_Click(object sender, EventArgs e) { if (File.Exists(fileNameInput)) { // alten Inhalt der Datenliste löschen, um beim wiederholten Mal Daten nicht doppelt erscheinen daten.Clear(); // Reader initialisieren, Schleife, solange Daten noch einzulesen sind, Zeile einlesen und der Datenliste hinzufügen // Reader schließen und entsorgen (beim Ende von Using) using (StreamReader rdr = new StreamReader(fileNameInput)) while (!rdr.EndOfStream) daten.Add(new Data(rdr.ReadLine())); // Datenliste binden dgv.DataSource = daten; } } private void BtnSave_Click(object sender, EventArgs e) { // Writer initialisieren // Schleife über alle Elemente in der Datenliste, zeilenweise in Datei ausgeben // Writer schließen und entsorgen using (StreamWriter wrt = new StreamWriter(fileNameOutput)) foreach (var item in daten) wrt.WriteLine(item.ToString()); } public class Data { public Data(string line) { var cols = line.Split(';'); for (int i = 0; i < cols.Length; i++) { if (i == 0) Column1 = cols[i]; if (i == 1) Column2 = cols[i]; if (i == 2) Column3 = cols[i]; } } public override string ToString() => $"{Column1};{Column2};{Column3}"; public string Column1 { get; set; } public string Column2 { get; set; } public string Column3 { get; set; } } } }
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Als Antwort markiert tklustig Samstag, 20. April 2019 12:50
Alle Antworten
-
Wenn ich an der richtigen Stelle diesen Code einfüge, ist der Bug behoben. Warum dem so ist, entzieht sich jedoch meiner Kenntnis. Kann das jemand erläutern, bitte?!
this.DataGridView_CSVContent.CurrentCell = this.DataGridView_CSVContent[0,zeilenAnzahl];
- Bearbeitet tklustig Freitag, 19. April 2019 20:04
-
Hi THomas,
warum machst Du Dir so viel Stress? Warum nutzt Du nicht eine einfache Datenbindung und bearbeitest in der Logik ausschließlich die Datenquelle. Als Datenquelle nutzt Du am besten eine typisierte Liste mit Datenobjekten eines Typs (einer Klasse), die mindestens pro Spalte eine Eigenschaft enthält. Deine splitLst kannst dann einfach aus diesen Datenobjekten füllen, z.B. mit einem AddRange und einer Methode der Klasse, die eine Liste der Eigenschaftswerte liefert.--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks -
Ist das in diesem Fall nicht overheaded?
Auslesen muss ich die Datenquelle(CSV Datei) so oder so. Die Spalteninhalte der Property einer neuen Klasse zuzuweisen ergibt für mich keinen erkennbaren Vorteil. Hier der funktionale Code, wie ich ihn derzeit verwende. Wie würdest Du das alternativ im Sinne der von Dir erwähnten Datenbindung machen?
#region Sichert Zelländerungen in die CSV Datei private void saveToolStripMenuItem_Click(object sender, EventArgs e) { try { _logger.Info("Load succesfully saveToolStripMenuItem_Click()"); string message = String.Empty, csvContentUnordered = String.Empty; int zeilenAnzahl = DataGridView_CSVContent.Rows.Count - 1, spaltenAnzahl; Verschluesselung encryptDecrypt = new Verschluesselung(); List<string> listPassword = new List<string>(); List<string> listUsername = new List<string>(); List<string> listPasswordEncrypted = new List<string>(); List<string> listUsernameEncrypted = new List<string>(); List<string> splitList = new List<string>(); if (EditGrid) { message = "Warum wollen Sie speichern? Ändern Sie erst einen beliebigen Zellenwert."; this.Ausgabe(message, "Warnung", MessageBoxIcon.Question); _logger.Info("Informed user, saving is nonsens without having done any changes"); return; } /* Die Property CurrentCell muss implementiert werden, damit alle Änderungen übernommen werden. Näheres dazu hier: https://social.msdn.microsoft.com/Forums/de-DE/46cc3af5-490b-490f-8c4e-f6e77cd09bc1/gridview-wird-nicht-korrekt-ausgelsen?forum=visual_studiode */ for (int reihe = 0; reihe < zeilenAnzahl; reihe++) { spaltenAnzahl = DataGridView_CSVContent.Rows[reihe].Cells.Count; DataGridView_CSVContent.CurrentCell = DataGridView_CSVContent[0, zeilenAnzahl]; try { for (int spalte = 0; spalte < spaltenAnzahl; spalte++) { splitList.Add(DataGridView_CSVContent.Rows[reihe].Cells[spalte].Value.ToString()); } } catch (NullReferenceException er) { message = " Die GridView hat einen invaliden Aufbau! Sie dürfen die Struktur nicht verändern. Haben Sie vielleicht Zellinhalte gelöscht?"; this.Ausgabe(message, "Error", MessageBoxIcon.Error); _logger.Warn("Informed user, it's not allowed removing any items from GridView{0}{1}", Environment.NewLine, er.Message); return; } } String[] splitArray = splitList.ToArray(); for (int i = 1; i <= splitArray.Length; i++) { if (i % 5 == 0) { listUsername.Add(splitArray[i - 2]); listPassword.Add(splitArray[i - 1]); } } _logger.Info("Succesfully added username and password from GridView to generic list"); foreach (string item in listUsername) { listUsernameEncrypted.Add(encryptDecrypt.EncryptString(item)); } foreach (string item in listPassword) { listPasswordEncrypted.Add(encryptDecrypt.EncryptString(item)); } _logger.Info("Succesfully encrypted every username and password from GridView"); string path = Path.Combine(rootFolder, filename); StreamWriter objWriter = new StreamWriter(path); for (int reihe = 0; reihe < zeilenAnzahl; reihe++) { if (reihe > 0) objWriter.Write(Environment.NewLine); spaltenAnzahl = DataGridView_CSVContent.Rows[reihe].Cells.Count; DataGridView_CSVContent.CurrentCell = DataGridView_CSVContent[0, zeilenAnzahl]; for (int spalte = 0; spalte < spaltenAnzahl; spalte++) { if (spalte < spaltenAnzahl - 1) { if (spalte == spaltenAnzahl - 2) objWriter.Write(listUsernameEncrypted[reihe] + ";"); else objWriter.Write(DataGridView_CSVContent.Rows[reihe].Cells[spalte].Value.ToString() + ";"); } else objWriter.Write(listPasswordEncrypted[reihe]); } } objWriter.Close(); message = "Ihre Änderungen wurden in die Datei " + filename + " übernommen. Username und Passwort wurden verschlüsselt eingetragen!"; this.Ausgabe(message, "Info", MessageBoxIcon.Information); _logger.Info("Succesfully wrote content of GridView into file {0}", filename); } catch (Exception er) { _logger.Error(er.Message + Environment.NewLine + er.ToString()); string message = "Unbekannter Fehler. Die Ursache wurde protokolliert." + Environment.NewLine + "Bitte informieren Sie den Entwickler thomas.kipp@automotivesystems.de"; this.Ausgabe(message, "Error", MessageBoxIcon.Error); } } #endregion
- Bearbeitet tklustig Freitag, 19. April 2019 20:18
-
Hi Thomas,
nachfolgend eine kleine Demo (ohne Designer, einfach in eine leere Form kopieren). Mit dem obersten Button wird eine CVS-Datei (Semikolon-separiert) geladen und im DataGridView angezeigt, dann können die Zellen geändert werden, mit dem zweiten Button können die aktuellen Daten wieder in einer CSV-Datei abgelegt werden.Wenn Du da noch die Befehle zur Fehlerprotokollierung hinzufügst, dann leibt das Programm doch bedeutend kürzer.
using System; using System.Collections.Generic; using System.IO; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Load += new System.EventHandler(this.Form02_Load); } // Arbeit ohne Designer in einer leeren Form private Button btnLoad = new Button() { Text = "Laden", Dock = DockStyle.Top }; private Button btnSave = new Button() { Text = "Speichern", Dock = DockStyle.Top }; private DataGridView dgv = new DataGridView() { Dock = DockStyle.Top }; private string fileNameInput = @"Form03Demo.csv"; private string fileNameOutput = @"Form03Demo_neu.csv"; private List<Data> daten = new List<Data>(); private void Form02_Load(object sender, EventArgs e) { this.Controls.AddRange(new Control[] { dgv, btnSave, btnLoad }); btnLoad.Click += BtnLoad_Click; btnSave.Click += BtnSave_Click; } private void BtnLoad_Click(object sender, EventArgs e) { if (File.Exists(fileNameInput)) { // alten Inhalt der Datenliste löschen, um beim wiederholten Mal Daten nicht doppelt erscheinen daten.Clear(); // Reader initialisieren, Schleife, solange Daten noch einzulesen sind, Zeile einlesen und der Datenliste hinzufügen // Reader schließen und entsorgen (beim Ende von Using) using (StreamReader rdr = new StreamReader(fileNameInput)) while (!rdr.EndOfStream) daten.Add(new Data(rdr.ReadLine())); // Datenliste binden dgv.DataSource = daten; } } private void BtnSave_Click(object sender, EventArgs e) { // Writer initialisieren // Schleife über alle Elemente in der Datenliste, zeilenweise in Datei ausgeben // Writer schließen und entsorgen using (StreamWriter wrt = new StreamWriter(fileNameOutput)) foreach (var item in daten) wrt.WriteLine(item.ToString()); } public class Data { public Data(string line) { var cols = line.Split(';'); for (int i = 0; i < cols.Length; i++) { if (i == 0) Column1 = cols[i]; if (i == 1) Column2 = cols[i]; if (i == 2) Column3 = cols[i]; } } public override string ToString() => $"{Column1};{Column2};{Column3}"; public string Column1 { get; set; } public string Column2 { get; set; } public string Column3 { get; set; } } } }
--
Best Regards / Viele Grüße
Peter Fleischer (former MVP for Developer Technologies)
Homepage, Tipps, Tricks- Als Antwort markiert tklustig Samstag, 20. April 2019 12:50
-
Okay. Überzeugt :=)
Eine Frage habe ich noch: Warum überschreibst du in der Klasse Data die toString()-Methode? Was erwirkt...
=> $"{Column1};{Column2};{Column3}";
genau. Ist Dein Konstrukt die kürzere Variante von:
public override string ToString() { return Column1+Column2+Column3; }
?
-
Hi,
zu $"...{Referenz}..." siehe:
$ – Zeichenfolgeninterpolation (C#-Referenz)
Gruß, Stefan
Microsoft MVP - Visual Developer ASP/ASP.NET (2001-2018)
https://www.asp-solutions.de/ - IT Beratung, Softwareentwicklung, Remotesupport -
Hallo Thomas,
mit => wird ein Lambdaausdruck eingeleitet. Einfach ausgedrückt ist das eine Funktion mit oder ohne Rückgabewert.
Bei der Zeichenverkettung mit $ oder string.Format werden Ressourcen eingespart.
Bei der Zeichenverkettung mit + werden immer unnötige instanzen der Klasse String erstellt.
Column1 + Column2 ergibt eine neue String Klasse mit dem Inhalt aus 1 und 2
Column1/2 + Column3 ergib wieder eine neue Sting Klasse.
Es geht nicht um die verkürzte Schreibweise sondern um die Einsparung von Ressourcen.
Wenn man so etwas in einer Schleife macht, kann es unter umständen zur einer Stackoverflow Exception kommen
Gruß Thomas
13 Millionen Schweine landen jährlich im Müll
Dev Apps von mir: UWP Segoe MDL2 Assets, UI Strings