Laden...

RowStatus = Added wird nicht bemerkt

Erstellt von Vexta vor 19 Jahren Letzter Beitrag vor 17 Jahren 7.674 Views
V
Vexta Themenstarter:in
19 Beiträge seit 2005
vor 19 Jahren
RowStatus = Added wird nicht bemerkt

Hallo,

auf einer Form habe ich eine Schaltfläche 'Neu', die löst folgenden Code aus:

[CHSARP]
this.BindingContext[dsGebTag1, "gebTag"].AddNew();
this.BindingContext["gebTag"].EndCurrentEdit();
[/CHSARP]

Dann editiere ich meine Textfelder.
Im ClosingEvent der Form möchte ich abfangen, ob noch ungespeicherte Sätze
vorhanden sind, wenn der Anwender auf 'Beenden' oder X drückt.
Dafür sieht mein Code so aus:

[CHSARP]
DataTable dt = dsGebTag1.Tables["gebTag"];
DataRow[] rChanged = dt.Select(null, null, DataViewRowState.Unchanged);
DataRow[] rAdded = dt.Select(null, null, DataViewRowState.Added);
if(rChanged.Length < dt.Rows.Count | rAdded.Length > 0)
{
DialogResult res = MessageBox.Show("Es sind ungespeicherte Daten vorhanden - Trotzdem beenden?",
"Achtung",
MessageBoxButtons.YesNo);
if(res == DialogResult.No)
e.Cancel = true;
}
else
MessageBox.Show("Keine Daten geändert"); }
[/CHSARP]

Problem ist nun, dass das ClosingEvent nicht immer bemerkt, wenn ein Satz hinzugefügt (oder auch geändert) wurde.
Gehe ich direkt nach dem Hinzufügen und Editieren der Felder auf Beenden, rufe also das ClosingEvent auf, bemerkt er es NICHT, blättere ich vorher, z. B. in einem DataGrid, wird der zugefügte Satz bemerkt.

Wie kann ich erreichen, dass das ClosingEvent das Hinufügen (Ändern) sofort bemerkt?

Tschau
Vexta

_
416 Beiträge seit 2005
vor 19 Jahren

Hallo

das Problem hat mir auch schon zur genüge graue Haare gebracht. Und speichert ein DataGrid die Änderungen solang nicht ab (d.h. schreibt sie nicht in die darunterleigende Tabelle) bis mal aus der Zeile herausgegangen ist, d.h. der Editmodus (kleiner Stift auf der linken Seite) beendet wurde. Leider werden verlässt man nur eine Zelle wenn man im Grid umherwandert oder ein komplett anderes Control den Focus bekommen. Und beim klick auf den Schließenknopf verliert das Grid nicht den Focus und die Zelle wird nicht gespeichert.

Ich benutz beim editieren immer gern den CSharp-Knopf. Da enstehen keine Schreibfehler mit [CHSARP] 😉

V
Vexta Themenstarter:in
19 Beiträge seit 2005
vor 19 Jahren

jetzt hab ich erst mal erfolgreich den C#-Button gesucht =)

und zum eigentlichen Thema:
8o - dass heisst, du hast graue Haare und bislang keine Lösung?

Ich habs in meinem ClosingEvent mal mit

	this.BindingContext[dt].EndCurrentEdit();

oder


if(dt.Rows.Count > 0)
{
	this.BindingContext[dt].Position = 0;
}

probiert, aber das hat erst mal nichts geholfen.

Auf dieses Problem müssen doch noch mehr gestossen sein?

Tschau
Vexta

_
416 Beiträge seit 2005
vor 19 Jahren

nein leider hab ich dafür keine Möglichkeit gefunden. Ein workaround wäre z.B. einem anderen Control (z.B. einem Button) den Fokus zuzuweisen. Ein anderer wäre sich eigene Columnstyles zu schreiben die sowieso alles sofort abspeichern. Letztere Lösung hab ich erfolgreich eingesetzt.

F
10.010 Beiträge seit 2004
vor 19 Jahren

Also Du musst auch den BindingContext nehmen den Du benutzt.


this.BindingContext[dsGebTag1, "gebTag"].EndCurrentEdit();

Und dann gibt es auch einen Einfahceren Weg nach änderungen zu suchen:


dsGebTag1.HasChanges()

4.221 Beiträge seit 2005
vor 19 Jahren

		private CurrencyManager CmPerson
		{
			get
			{
				return this.BindingContext[this.dataGrid1.DataSource,this.dataGrid1.DataMember] as CurrencyManager;
			}
		}

		private DsPerson.PersonRow CurrentPersonRow
		{
			get
			{
				DsPerson.PersonRow ret=null;
				CurrencyManager cmPerson=this.CmPerson;
				if (cmPerson.Position>-1)
				{
					ret=(cmPerson.Current as DataRowView).Row as DsPerson.PersonRow;
				}
				return ret;
			}
		}

		private void btnAddNewPerson_Click(object sender, System.EventArgs e)
		{
			CurrencyManager cmPerson=this.CmPerson;
			cmPerson.AddNew();
			//um noch was zu verändern (dynamische DefaultWerte oder so)..
			DsPerson.PersonRow currentRow=CurrentPersonRow;
			currentRow.Name="Hans";
		}

		private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			CurrencyManager cmPerson=this.CmPerson;
			if (cmPerson.Position>-1)
			{
				cmPerson.EndCurrentEdit();
			}
			if (this.dsPerson1.HasChanges())
			{
				if (MessageBox.Show("Save changes ?","Save",MessageBoxButtons.YesNoCancel)==DialogResult.Yes)
				{
					//in DB saven


					//wenn DB-saven ok war würde hier stehen
					//this.dsPerson1.AcceptChanges();

					//bei Fehler beim speichern 
					//e.Cancel=true;
				}
				else
				{
					//ist hier nicht relevant da das Form eh geschlossen wird
					//Alle Aenderungen verwerfen
					//this.dsPerson1.RejectChanges();
				}
			}
		}

		private void Form1_Load(object sender, System.EventArgs e)
		{
			this.dsPerson1.Person.AddPersonRow("Test");
			this.dsPerson1.AcceptChanges();
		}


Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

V
Vexta Themenstarter:in
19 Beiträge seit 2005
vor 19 Jahren

@FZelle:

Mit deinem Vorschlag zur Verwendung von BindingContext...EndCurrentEdit

this.BindingContext[dsGebTag1, "gebTag"].EndCurrentEdit()

klappts jetzt anscheinend. Ich dachte , dass ich mit folgengendem Codesnippet
eigentlich das gleiche tue ?


DataTable dt = dsGebTag1.Tables["gebTag"];
this.BindingContext[dt].EndCurrentEdit();

Wieso funktioniert das eine und das andere nicht?

Zu deinem zweiten Vorschlag:
HasChanges wirkt laut Hilfe auf das ganze DataSet. In einer Form, in der aber nur eine Table des DataSet bearbeitet wird, möchte ich nur die betroffenen Tabellen überprüfen. Das geht lt Hilfe mit HasChanges nicht, oder hab ich was übersehen?

@Programmierhans
Dein Code-Beispiel ist für mich Anfänger ziemlich erschlagend. Das gucke ich mir jetzt in aller Ruhe an.

Vielen Dank an alle!
Vexta

4.221 Beiträge seit 2005
vor 19 Jahren

Das wichtigste überhaupt wenn man mit DataBinding arbeitet:

  • Immer dieselben Parameter verwenden um den CurrencyManager zu holen.

this.BindingContext[dsGebTag1, "gebTag"];

//gibt nicht denselben CurrencyManager zurück wie

this.BindingContext[dsGebTag1.Tables["gebTag"],""];


this.BindingContext ist ein Indexer welcher einen BindingManagerBase (die BaseClass von CurrencyManager / PropertyManager) zurückliefert. Falls noch keiner existiert, so wird einer erstellt.

Um auf Dein Beispiel zurückzukommen.... der eine CurrencyManager sitzt auf der soeben erstellten Row (Position > -1)..... der andere aber nicht (der hat nicht mal mitbekommen dass bereits eine Detached - Row existiert.... weiss demzufolge auch nichts von Aenderungen....)

Auch das DataSet weiss noch nichts von den Aenderungen, da die Row noch Detached ist..... erst wenn die Row attached wird gibt HasChanges auch ein true zurück.

Uebrigens gibts HasChanges glaub auch auf TabellenEbene.

Somit immer:

--> Alle CurrencyManagers mit Position > -1 mit EndCurrentEdit abschliessen
--> Für die Tabellen oder einfacher für das DataSet HasChanges abfragen
--> User fragen ob gesichert werden soll (bei nein Ds.RejectChanges)
--> DB saven
--> bei Erfolg DataSet.AcceptChanges

Zugegeben das Beispiel ist ein wenig komlexer als nötig.... mir war es aber wichtig hier mal die Zusammenhänge aufzuzeigen.... denn man dort sooooo viel falsch machen (habe da schon die unmöglichsten Sachen gesehen)

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

V
Vexta Themenstarter:in
19 Beiträge seit 2005
vor 19 Jahren

So - jetzt hab ich mir das mal verinnerlicht.
Erst aber mal DANKE! - ausführlich und fundiert - super!

Original von Programmierhans

  
private CurrencyManager CmPerson  
{  
  get  
  {  
  	return this.BindingContext[this.dataGrid1.DataSource,this.dataGrid1.DataMember] as CurrencyManager;  
  }  
}  
  

Hier erstellst du den CurrencyManager als Eigenschaft, damit der Zugriff immer mit den gleichen Parametern erfolgt, siehe dein letztes Posting.

  
private DsPerson.PersonRow CurrentPersonRow  
{  
  get  
  {  
  	DsPerson.PersonRow ret=null;  
  	CurrencyManager cmPerson=this.CmPerson;  
  	if (cmPerson.Position>-1)  
  	{  
  		ret=(cmPerson.Current as DataRowView).Row as DsPerson.PersonRow;  
  	}  
  	return ret;  
  }  
}  
  

Hier komme ich nicht ganz klar, was bedeutet dieser Code, besonders die Zeile mit "ret =..." - und was bezweckst du damit?

Der Rest im Closing ist soweit klar, auch dein anderes Posting ist sehr hilfreich!
Nochmals vielen Dank, die Geschichte mit dem BindingContext ist mir wieder etwas klarer geworden.
😁 Ich hoffe noch mehr Antworten von dir zu bekommen...

Gruß
Vexta

4.221 Beiträge seit 2005
vor 19 Jahren

Original von Vexta

  
private DsPerson.PersonRow CurrentPersonRow  
{  
 get  
 {  
 	DsPerson.PersonRow ret=null;  
 	CurrencyManager cmPerson=this.CmPerson;  
 	if (cmPerson.Position>-1)  
 	{  
 		ret=(cmPerson.Current as DataRowView).Row as DsPerson.PersonRow;  
 	}  
 	return ret;  
 }  
}  
  

Hier komme ich nicht ganz klar, was bedeutet dieser Code, besonders die Zeile mit "ret =..." - und was bezweckst du damit?

Der Rest im Closing ist soweit klar, auch dein anderes Posting ist sehr hilfreich!
Nochmals vielen Dank, die Geschichte mit dem BindingContext ist mir wieder etwas klarer geworden.
😁 Ich hoffe noch mehr Antworten von dir zu bekommen...

Gruß
Vexta

Dieses Property dient dazu schnellen sicheren Zugriff auf die aktuelle Row des CurrencyManagers der Tabelle Person sicherzustellen (auch wenn er auf einer Row sitzt, welche noch nicht attached ist....

Wenn Du solche Sachen kapselst tippst Du nachher bei der Verwendung weniger und musst auch Fehler nur an einer Stelle korrigieren....

beim ret=... handelt es sich um den return - Value dieses Properties, welches mit null inizialisiert wird, und dann überschrieben wird, falls der cm auf einer Row sitzt.... wenn der cm auf keiner Row sitzt wird null zurückgegeben

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

563 Beiträge seit 2004
vor 17 Jahren

Hallo Programmiererhans

Gute Lösung! Warum verwendest du kein BindingSource? Da würdest du deine Propertys für den CurrencyManager gar nicht brauchen!

Gruss,
.unreal

4.221 Beiträge seit 2005
vor 17 Jahren

BindingSource ?

Muss was neues aus 2005 sein.... dieser Code funzt mit 2003 (und hoffentlich auch mit 2005)

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

563 Beiträge seit 2004
vor 17 Jahren

genau, BindingSource ist neu in 2005, sorry, hab nicht geguckt welche Version du verwendest.

.unreal

4.221 Beiträge seit 2005
vor 17 Jahren

Original von .unreal
hab nicht geguckt welche Version du verwendest.

Ist im übrigen eh schon ein älterer Artikel... ev. sogar aus VOR-2005 -Zeiten

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...