Laden...

DataGridView zeigt nach rowLeave-Event nichts an

Erstellt von RoyalRoy vor 4 Jahren Letzter Beitrag vor 4 Jahren 2.529 Views
R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren
DataGridView zeigt nach rowLeave-Event nichts an

Hallo C#ler,

ich beschäftige mich schon seit einiger Zeit mit C# und bin jetzt auf einen Fehler gestoßen, den ich mir nicht erklären kann.

Zum einfachen Verständnis habe ich ein einfaches Beispielprogramm geschrieben, um nicht unnötig viel Code durchlesen zu müssen.

Ich möchte ein DataGridView aus einem Array mit werten füllen. Durch ein Event, dass ausgelöst wird, wenn ich eine Zeile in der Tabelle verlasse (RowLeave), sollen die Werte verändert und anschließend erneut über das Datagridview ausgegeben werden.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace tabelHandlerTest
{
    public partial class Form1 : Form
    {
        DataTable data = new DataTable();
        public int i = 0;
        public bool loadReady = false;
        private double[] xValues = new double[0];

        public Form1()
        {
            InitializeComponent();
            xValues = new double[10];       // Array mit Werten 
            for (int i = 0; i < 10; i++)    // Arrays füllen
            {
                xValues[i] = i;
            }           
            tableWrite();                   // DataGridView mit Werten aus Array füllen
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            if (loadReady == true)
            {      
                xValues[4] = 444;           // Werte im Array verändern
                data.Clear();               // DataGridView leeren
                data.Rows.Clear();
                data.Columns.Clear();
                tableWrite();               // DataGridView erneut beschreiben
            }
        }

        private void tableWrite()           // DataGridView mit Werten aus Array füllen
        {  
            data.Columns.Add("X");
            for (int i = 0; i < 10; i++)
            {
                data.Rows.Add(xValues[i]);
            }
            dataGridView1.DataSource = data;
        }

        private void Form1_Activated(object sender, EventArgs e)    
        {
            loadReady = true;
        } // dient nur dazu, dass das rowLeave-Event erst nach dem Laden des Forms seinen Code ausführt
    }
}

Beim Ausführen funktioniert auch alles wunderbar, bis man das rowLeave-Event auslöst, indem man die Zeile durch Mausclick oder Pfleiltasten ändert.
Denn dann ist das DataGridView einfach leer, sodass keine Tabelle (Zeilen, Spalten und usw.) angezeigt werden.
Schaut man aber beim Debuggen des Programms in den Inhalt des DataGridView, so sind die geänderten Daten vorhanden, werden aber nur nicht angezeigt.

Das Problem beschäftigt mich jetzt schon eine ganze Weile und ich weis nicht, wie ich das Problem lösen kann oder woran es überhaupt liegt.

Ich hoffe ihr könnt mir helfen. Schon mal Danke im voraus.
MfG RoyalRoy

1.040 Beiträge seit 2007
vor 4 Jahren

Also dein Vorgehen ist irgendwie merkwürdig.

Was passiert, wenn du nur den Wert in der DataTable änderst?

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Wenn ich den wert nur in der Tabelle ändere, dann steht da der geänderte Wert.

Ich will aber nicht den Wert in der Tabelle ändern, sondern nur die geänderten Werte aus dem Array in der Tabelle anzeigen und das über das rowLeave-Event.

In dem Array befinden sich die Werte mit denen ich arbeite und diese will ich nur über die Tabelle optisch auflisten.

Der Fehler muss zwangsläufig mit dem rowLeave Event zusammenhängen, dann ohne das Event klappt es perfekt. (DataTable über Button neu beschreiben und darstellen)

1.040 Beiträge seit 2007
vor 4 Jahren

Du änderst halt die Daten des Grids, während du noch in einem Event der aktuellen Daten hängst. Kann durchaus schon die Ursache sein.

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Hast du eine Idee wie ich das umgehen kann.

Meine Intension ist es über das rowLeave-Event die Daten von dem DataGridView einzulesen (in Array speichern), zu verarbeiten uns sofort bearbeitet wieder im DataGridView anzuzeigen. (Also quasie die Tabelle neu zu überschreiben)

Denn die Werte werden richtig in den Datensatz übernommen, bloß nicht mehr angezeigt.

4.931 Beiträge seit 2008
vor 4 Jahren

Lösche mal vor dem Befüllen die DataSource:


dataGridView1.DataSource = null;

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Hy, danke für die Antworten.
Leider bringt er mir, egal an welcher stelle, diesen Fehler.

1.040 Beiträge seit 2007
vor 4 Jahren

Siehe oben, du ziehst dir die Daten unterm Arsch weg.

Kannst du nochmal genau erklären, was du machen möchtest?
Du zeigst Daten aus einem Array im Grid an, bearbeitest sie dort und möchtest sie in das Array zurückschreiben, richtig? Dann ist doch die Anzeige schon korrekt?

4.931 Beiträge seit 2008
vor 4 Jahren

Du könntest zwar mittels [FAQ] Bestimmte Aktionen bis nach der laufenden GUI-Event-Behandlung verzögern den Fehler eliminieren, aber besser wäre es wirklich du aktualisierst nur die DataTable (anstatt diese zu löschen und neu zu erstellen).

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Siehe oben, du ziehst dir die Daten unterm Arsch weg.
Kannst du nochmal genau erklären, was du machen möchtest?
Du zeigst Daten aus einem Array im Grid an, bearbeitest sie dort und möchtest sie in das Array zurückschreiben, richtig? Dann ist doch die Anzeige schon korrekt?

Meine Intension ist es über das rowLeave-Event die Daten von dem DataGridView einzulesen (in Array speichern), zu verarbeiten uns sofort bearbeitet wieder im DataGridView anzuzeigen. (Also quasi die Tabelle neu zu überschreiben)

Nachdem das rowLeave-Event getriggert wurde, sollen die Werte bearbeitet (z.B mit 2 multipliziert) und anschließend die neuen bearbeiteten Werte wieder in der Tabelle angezeigt weeden.

Es funktioniert auch soweit, dass ich beim Debuggen in der DataSet Schnellansicht die geänderten Werte sehe, aber diese im nächsten Schritt nicht im DataGridView auf dem Forms nicht angezeigt werden.

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Du könntest zwar mittels
>
den Fehler eliminieren, aber besser wäre es wirklich du aktualisierst nur die DataTable (anstatt diese zu löschen und neu zu erstellen).

Ich dachte ich habe nur den DataTable aktualisiert, indem ich alle alten Werte (Zeile- und Spalten-Header) rauslösche und anschließend mit meinen neuen Werten überschreibe. Ich erstell ja ansich kein neues DataGridView.

Die bearbeiteten Werte stehen ja bereits in der DataSet-Schnellansicht beim debuggen ordnungsgemäß drin, werden aber beim weiteren Ausführen nicht im DataGridView des Forms angezeigt.

DataSet-Schnellansicht beim debuggen:

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Und das Forms nach dem weiteren ausführen des Programms:
Die Daten sind zwar vorhanden und richtig, werden aber nur nicht angezeigt.

4.931 Beiträge seit 2008
vor 4 Jahren

Laß mal das Löschen und Neuerstellen der Spalten sein, sondern erstelle diese nur einmalig:


        public Form1()
        {
            InitializeComponent();
            xValues = new double[10];       // Array mit Werten
            for (int i = 0; i < 10; i++)    // Arrays füllen
            {
                xValues[i] = i;
            }

            data.Columns.Add("X");
            tableWrite();                   // DataTable mit Werten aus Array füllen

            dataGridView1.DataSource = data; // einmalige Zuweisung
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            if (loadReady == true)
            {
                xValues[4] = 444;       // Werte im Array verändern
                tableWrite();           // DataTable erneut beschreiben
            }
        }

        private void tableWrite()           // DataTable mit Werten aus Array füllen
        {
            data.Clear();
            for (int i = 0; i < 10; i++)
            {
                data.Rows.Add(xValues[i]);
            }
        }

        private void Form1_Activated(object sender, EventArgs e)
        {
            loadReady = true;
        } // dient nur dazu, dass das rowLeave-Event erst nach dem Laden des Forms seinen Code ausführt

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Laß mal das Löschen und Neuerstellen der Spalten sein, sondern erstelle diese nur einmalig:

Ansich eine gute Idee, dann würde es funktionieren.
Aber:
In meinem richtigen Programm werden die Spalten dynamisch angelegt. Das heißt, dass ich nach der Eingabe der Werte über die Tabelle, die Werte bearbeite und entsprechend dem entstehenden Ergebnis, spalten entferne, hinzufüge, umbenenne, vertausche oder etc.
--> Das ist also nicht so einfach möglich.


Du könntest zwar mittels [FAQ] Bestimmte Aktionen bis nach der laufenden GUI-Event-Behandlung verzögern den Fehler eliminieren, aber besser wäre es wirklich du aktualisierst nur die DataTable (anstatt diese zu löschen und neu zu erstellen) BeginInvoke(new Action (tableWrite));

Würde auch funktionieren, wenn das rowLeave-Event nicht immer einmal beim Starten des Programms ausgelöst werden würde.
--> Dadurch hängt sich das Programm auf und befindet sich in einer Art Endlosschleife, sodass sich das rowLeave-Event immer wieder selbst triggert.

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Weiterhin habe ich gerade gesehen, dass ich das Form1_Activated-Event nicht benutzen kann.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;

namespace tabelHandlerTest
{
    public partial class Form1 : Form
    {
        DataTable data = new DataTable();
        public int i = 0;
        private double[] xValues = new double[0];

        public Form1()
        {
            InitializeComponent();
            xValues = new double[10];       // Array mit Werten 
            for (int i = 0; i < 10; i++)        // Arrays füllen
            {
                xValues[i] = i;
            }
            data.Columns.Add("X");
            tableWrite();                            // DataGridView mit Werten aus Array füllen
            dataGridView1.DataSource = data;
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
             xValues[4] = 444;           // Werte im Array verändern
             tableWrite();                   // DataGridView erneut beschreiben
        }

        private void tableWrite()           // DataGridView mit Werten aus Array füllen
        {            
            for (int i = 0; i < 10; i++)
            {
                data.Rows.Add(xValues[i]);
            }            
        }
    }
}

U
69 Beiträge seit 2019
vor 4 Jahren

Hi RoyalRob,

ich sehe da noch ein anderes Problem:

Das heißt, dass ich nach der Eingabe der Werte über die Tabelle, die Werte bearbeite und entsprechend dem entstehenden Ergebnis, spalten entferne, hinzufüge, umbenenne, vertausche oder etc.

Ich bin der Meinung, dass du im RowLeave-Event nur die alten Werte zur Verfügung hast. Im DataGridViewCellEventArgs steht zwar welche Zelle bearbeitet wurde, aber der sender beinhaltet immernoch die alten Daten. Also kannst du die Tabelle nicht anhand der Eingabe anpassen.

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Hi Urza 😁

Ich bin der Meinung, dass du im RowLeave-Event nur die alten Werte zur Verfügung hast. Im DataGridViewCellEventArgs steht zwar welche Zelle bearbeitet wurde, aber der sender beinhaltet immernoch die alten Daten. Also kannst du die Tabelle nicht anhand der Eingabe anpassen.

Daran hatte ich auch erst gedacht, aber wenn man beim Debuggen nach dem ausführen von tableWrite im Handler des rowLeave-Events stoppt, dann stehen die neuen Werte beraits in der DataSet Schnellansicht, welche die aktuellen Daten des DatagridView wiederspiegelt.
(DataSet Schnellansicht ist unter Visual Studio 2017 der aktuelle Inhalt den man beim Debuggen einsehen kann.)

Daher hatte ich das schon als Ursache ausgeschlossen. Es kann natürlich sein, dass ich mich irre, aber für mich klingt das logisch. 🤔

4.931 Beiträge seit 2008
vor 4 Jahren

BeginInvoke(new Action (tableWrite));

Würde auch funktionieren, wenn das rowLeave-Event nicht immer einmal beim Starten des Programms ausgelöst werden würde.
--> Dadurch hängt sich das Programm auf und befindet sich in einer Art Endlosschleife, sodass sich das rowLeave-Event immer wieder selbst triggert.

Und dagegen hilft [FAQ] Event nur bei Benutzeraktion auslösen, nicht bei programmtechnischer Änderung.
In die FAQs zu schauen lohnt sich 😉

U
69 Beiträge seit 2019
vor 4 Jahren

Ich denke du beziehst dich auf deinen Screenshot mit der DataSet-Schnellansicht weiter oben...
Du hast die 444 im Code in das Array geschrieben aus dem in deinem tableWrite die neue Tabelle erstellt wird. Also findest du die 444 natürlich auch in der Schnellansicht.
Du solltest dir den Inhalt des DataSets vor tableWrite ansehen, denn du erwartest ja, dass der User die Daten über die UI ändert.

“Knowledge cannot replace friendship. I'd rather be an idiot than lose you.”

  • Patrick to Spongebob
R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Ich bin mir nicht sicher, ob ich dich richtig verstehe, aber mein Problem ist nicht das einlesen des eingegebenen Wertes über die Tabelle, sondern das wieder ausgeben.
Nach dem kopieren der Daten aus der Tabelle in das Array, sind die Werte im Array gespeichert und werden dort geändert. Das ist der Stand bei dem das Beispielprogramm hier anfängt und bis dahin funktioniert auch alles super.

Ich möchte nun die neuen Werte aus dem Array (Beispiel hier 444 und natürlich auch den Rest der Spalte) in die Tabelle schreiben. (quasi die alten Werte in der Tabelle durch die neuen Werte aus dem Array ersetzen).

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Und dagegen hilft
>
.
In die FAQs zu schauen lohnt sich 😉

Danke für die Suche, aber den Artikel hatte ich auch schon vor der Nase.

Den ersten Lösungsansatz hatte ich auch schon probiert, jedoch fehlt mir eine Möglichkeit zu sagen, dass er nur beim Starten des Programms den Handler nicht ausführen soll. Das rowLeave-Event wird direkt nach dem Konstruktor Form1 ausgeführt.

--> Ich bräuchte ein Event, dass mir sagt, dass meine Tabelle fertig geladen ist.
(DataBindingComplete, DataSorceChanged und etc. werden noch vor dem erstmalige aufrufen von rawLeave getriggert)
Auf einen Counter der ausschließt, ob das Event ausgeführt werden soll, wollte ich verzichten, da das nun wirklich nicht schön ist.

An die letzte Alternative, die Klasse zu überschreiben habe ich mich noch nicht rangetraut, werde ich aber nun wahrscheinlich doch machen müssen.

4.931 Beiträge seit 2008
vor 4 Jahren

Das wird aber vom DataGridView m.E. nicht direkt unterstützt.
Du mußt bedenken, daß es sich hierbei um DataBinding handelt, d.h. es wird auf Änderung der Daten gehorcht (aber nicht grundsätzlich auf Änderung der kompletten Struktur).

Probiere aber mal eine DataTable mit 2 Spalten anzulegen und diese dann zu binden und lösche dann eine dieser Spalten und/oder füge mal eine neu hinzu (ohne die Daten zu löschen).

Wenn dies (doch) funktioniert, dann könntest du entsprechend so vorgehen (anstatt alle Zeilen und Spalten zu löschen).

Edit: ich beziehe mich auf deinen vorletzten Beitrag.

PS: Bzgl. deinem Event-Trigger-Problem verwende doch auch dafür ein boolsches Flag, welches den ersten Aufruf von rowLeave ignoriert.

R
RoyalRoy Themenstarter:in
24 Beiträge seit 2019
vor 4 Jahren

Probiere aber mal eine DataTable mit 2 Spalten anzulegen und diese dann zu binden und lösche dann eine dieser Spalten und/oder füge mal eine neu hinzu (ohne die Daten zu löschen).

Mehrere Spalten anlegen und entfernen ist kein Problem, ich weiß bloß nicht genau, was du damit meinst das ich die Spalte löschen soll, ohne die Daten zu löschen. Ich kann mit data.Columns.Remove(...) eine bestimme Spalte oder mit data.Columns.Clear() alle Spalten löschen, das Binding und damit das DataGridView bleiben ja bestehen.

PS: Bzgl. deinem Event-Trigger-Problem verwende doch auch dafür ein boolsches Flag, welches den ersten Aufruf von :::

Das Problem hierbei war ja, das ich keinen Zeitpunkt finde (durch bestimmtes Event oder Abschnitt im Code), das Flag zurückzusetzen, um das rowLeave zuzulassen, da es zwischen den Funktionen aufgerufen wird.

Ich hab derweil noch einmal einen Kommentar weiter oben aufgegriffen und es läuft ersteinmal soweit, dass es die Daten durch das rowLeave verändert.

Nun muss ich noch schauen, dass ich abfrage, ob ich die Zelle verändert habe, da ich sonst immer das rowLeave trigger und anschließend immer die erste Zelle ausgewählt ist und ich nie andere Zellen auswählen kann um diese zu verändern. 😁
Aber ich denke, das bekomme ich hin.

Danke für die ganzen Tipps, ihr habt mir echt geholfen. 👍


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//using System.Threading;

namespace tabelHandlerTest
{
    public partial class Form1 : Form
    {
        DataTable data = new DataTable();
        bool useRowLeaveEvent = false;
        private double[] xValues = new double[0];

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            xValues = new double[10];               // Array mit Werten 
            for (int i = 0; i < 10; i++)            // Arrays füllen
            {
                xValues[i] = i;
            }
            tableWrite();                           // DataGridView mit Werten aus Array füllen
            useRowLeaveEvent = true;
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            if(useRowLeaveEvent == true)
            {
                useRowLeaveEvent = false;
                xValues[4] = xValues[4] + 1;        // Werte im Array verändern
                data.Clear();
                data.Columns.Clear();
                BeginInvoke(new Action(tableWrite));
                useRowLeaveEvent = true;
            }
        }

        private void tableWrite()                   // DataGridView mit Werten aus Array füllen
        {
            data.Columns.Add("X");
            for (int i = 0; i < 10; i++)
            {
                data.Rows.Add(xValues[i]);
            }
            dataGridView1.DataSource = data;
        }
    }
}