Verwendete Technologien: LINQ
So, ich hab nun das gesamte Forum durchgelesen bzgl CurrencyManager und ich komm einfach auf keine Lösung in meinem Fall.
Ich habe eine LINQ to ENTITIES Query - Result.. Dieses wird in einem Sortierbaren DGV angezeigt.
private void wndPersonen_Load(object sender, EventArgs e)
{
context = new oEntities();
var query = from p in context.person
orderby p.Nachname
select new ListViewObject_wndPersonen
{
Person = p,
Nachname = p.Nachname,
Vorname = p.Vorname,
Wohnort = p.PLZ + " " + p.Wohnort
};
dataGridView1.DefaultCellStyle = Vars.CellStyle;
bs = new SortableBindingList<ListViewObject_wndPersonen>(query);
dataGridView1.DataSource = bs;
dataGridView1.Columns["Person"].Visible = false;
}
Nun möchte ich via Doppelklick einen Eintrag aus meiner DGV bearbeiten können. Funktioniert auch soweit, aber mein DGV wird erst aktualisiert, wen ich die Anwendung neu starte...
private void btnBearbeiten_Click(object sender, EventArgs e)
{
frmPerson frm = new frmPerson((dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].DataBoundItem as ListViewObject_wndPersonen).Person);
if (frm.ShowDialog() == DialogResult.OK)
{
context.SaveChanges();
// HIER UPDATE ...
}
else
{
// Abbrechen geklickt...
}
}
Woran liegts? Ich hab einiges mit dem Currency Manager versucht aber hab kein Update hinbekommen... 😦
Hi!
Probierma, der frmPerson
die dataGridView1.DataSource as BindingSource
mitzugeben. Da ist ja die gewünschte Person als .Current
enthalten.
Und zur Übernahme der Änderungen BindingSource.EndEdit()
ausführen.
Nix mit context.SaveChanges()
Der frühe Apfel fängt den Wurm.
Vielleicht findest Du hier noch ein paar nützliche Tipps.
Grüsse
Daniel
Space Profile
Wer nicht fragt, der nicht gewinnt
Hi!
Probierma, der
frmPerson
diedataGridView1.DataSource as BindingSource
mitzugeben. Da ist ja die gewünschte Person als.Current
enthalten.
Und zur Übernahme der ÄnderungenBindingSource.EndEdit()
ausführen.
Nix mitcontext.SaveChanges()
Ok, werde ich mal versuchen. Habe aber noch zwei Fragen:
Inzwischen habe ich das Update hinbekommen mit dem CurrencyManager: an die datagridview1.datasource gebunden und dann via cm.Refresh() updaten (warum auch immer das anfangs nicht geklappt hat..)
Hi!
Für mich ist das Rückspeichern gemachter Änderungen prinzipiell eine Aktion, die vom User auszugehen hat, mit einem Save-Button.
Er kann sich Daten abholen, nach Herzenslust drin rumwursteln, und iwann entscheidet er "so, fertig, abspeichern bitte".
So funktioniert Word, Excel, jeder Editor, und auch diese ForenSoftware zur Eingabe von Posts. 😉
Mittm Databinding hat SaveChanges() ja nix zu tun.
Ich kenn mich mittm DataContext nicht soo aus, nur vonne Datasets weißich, wenn in einem Control ein Datensatz bearbeitet wird, geschieht die Aktualisierung anderer an denselben Datensatz anzeigender Controls erst, wenn der aktuelle Datensatz gewechselt wird.
Dein Datensatz wird aber nicht gewechselt, wenn du das Eingabeform schließt.
Daher musste die Aktualisierung erzwingen, mit BindingSource.EndEdit()
(Also denkich jedenfalls mal, fändich logisch)
Der frühe Apfel fängt den Wurm.
Hi!
Probierma, der
frmPerson
diedataGridView1.DataSource as BindingSource
mitzugeben. Da ist ja die gewünschte Person als.Current
enthalten.
Und zur Übernahme der ÄnderungenBindingSource.EndEdit()
ausführen.
Nix mitcontext.SaveChanges()
Ich habe noch eine Frage bzgl. bindingsource.CancelEdit(): Warum funktioniert es im folgenden Code nicht, dass meine Änderungen am DataSource "rückgängig" gemacht werden?
Hier der Code meines frmMain:
//1. Abfrage..
//2. Databinding
m_bindingsource= new BindingSource();
m_bindingsource.DataSource = allData; //LINQ Resultat ...
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = m_bindingsource;
//...irgendwann dann mal ein Formular aufrufen, welches den aktuellen Datensatz bearbeiten kann
frmPerson frm = new frmPerson(dataGridView1.DataSource as BindingSource);
if (frm.ShowDialog() == DialogResult.OK)
{
//Änderungen an Datasource übernehmen
m_bindingsource.EndEdit();
//Änderungen in Datenbank übernehmen
//m_context.SaveChanges();
//DGV aktualisieren
cm.Refresh();
dataGridView1.Invalidate();
}
else
{
//Durchgeführte Änderungen an Datasource verwerfen
m_bindingsource.CancelEdit();
//FUNKTIONIERT LEIDER NICHT ...
}
Hier der Code von frmPerson
public frmPerson(BindingSource bs)
{
InitializeComponent();
//Verweis auf Person einholen
m_bindingsource = bs;
m_originalobject = ((ListViewObject_wndPersonen)m_bindingsource.Current).Person;
//Databinding an Steuerelemente um Änderungen am Objekt durchzuführen
textboxVorname.DataBindings.Add(new Binding("Text", ((ListViewObject_wndPersonen)m_bindingsource.Current).Person, datamember));
//...
}
Hmmmmpf ... 😕 MSDN und Google hat mir auf Anhieb nich wirklich weitergeholfen ..
Also erstmal ist das allerwichtigste, daß in frmPerson nicht der Datensatz gewechselt wird.
Und dann scheints so, dasser auch dann übernommen wird, wenn frmPerson geschlossen wird.
Also probieren, vorher zu canceln.
Was macht cm.Refresh
?
Der frühe Apfel fängt den Wurm.
cm.Refresh() is überflüssig, gehört da nicht rein - sind noch Reste aus der vorherigen Implementierung...
Ich wechsle im frmPerson allerdings keinen Datensatz...
EDIT:
Mein Gott... warum funktioniert das nicht . Muss ich irgendn Interface in meiner Klasse "Person" implementieren?
Also ich hab jetzt mal was mittm Dataset gebastelt.
Habe festgestellt, das Schließen des Forms führt zu BindingSource.EndEdit().
Also, wie gesagt, vorher canceln, nämlich im Code des Schließen-Buttons von frmPerson.
Der frühe Apfel fängt den Wurm.
Das Problem scheint definitiv ein anderes zu sein, aber ich finds einfach nicht... Ich poste mal alle relevanten Stellen... !
Wird eine MessageBox aufgerufen, so wird automatisch ein EndEdit aufgerufen, nach dem auf "JA" oder "NEIN" geklickt wurde. Kann man die "Automation" vollständig abschalten? Ich würde gerne BeginEdit(); CancelEdit(); und EndEdit() ausschließlich manuell aufrufen ...
IEditableObject eingebunden:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Windows.Forms;
namespace BusinessObjects
{
public abstract class ObjectBase : System.ComponentModel.IEditableObject
{
Hashtable props = null;
#region IEditableObject Members
public void BeginEdit()
{
if (null != props) return;
PropertyInfo[] properties = (this.GetType()).GetProperties(BindingFlags.Public | BindingFlags.Instance);
props = new Hashtable(properties.Length - 1);
for (int i = 0; i < properties.Length; i++)
{
if (null != properties[i].GetSetMethod())
{
object value = properties[i].GetValue(this, null);
props.Add(properties[i].Name, value);
}
}
}
public void CancelEdit()
{
if (null == props) return;
PropertyInfo[] properties = (this.GetType()).GetProperties(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < properties.Length; i++)
{
if (null != properties[i].GetSetMethod())
{
object value = props[properties[i].Name];
properties[i].SetValue(this, value, null);
}
}
props = null;
}
public void EndEdit()
{
props = null;
}
}
}
Klasse von ObjectBase ableiten:
public class ListViewObject_wndPersonen : ObjectBase { ... }
Bearbeiten-Button-Routine:
private void btnBearbeiten_Click(object sender, EventArgs e)
{
cm.Refresh();
frmPerson frm = new frmPerson(m_bindingsource);
frm.ShowDialog();
//Datenanzeige im datagridview aktualisieren
dataGridView1.Invalidate();
}
frmPerson:
public frmPerson(BindingSource bs)
{
InitializeComponent();
//Verweis auf Person einholen
m_bindingsource = bs;
m_originalobject = ((ListViewObject_wndPersonen)m_bindingsource.Current).Person;
//Databinding auf Steuerelemente
textBoxVorname.DataBindings.Add(new Binding("Text", m_bindingsource.Current, "Person.Vorname"));
//...
}
private void btnAbbrechen_Click(object sender, EventArgs e)
{
//Abbrechen Button ist immer erlaubt ...
m_bindingsource.CancelEdit();
//keine Validierung durchführen ...
this.CanClose = true;
}
private void frmPerson_FormClosing(object sender, FormClosingEventArgs e)
{
//Darf das Form geschlossen werden?
if (!this.CanClose)
{
e.Cancel = true;
}
m_bindingsource.EndEdit(); // < wird beim Schließen des Formulars NICHT automatisch aufgerufen
}
Ich hoffe, dass ich nun alles vom "logischen" her korrekt gemacht habe und einigen mit ähnlichen Problemen helfen konnte...
Ja, weißichauchnich. Meiner übernimmt die Änderungen, wenn ich ihn nicht dran hindere, und deinen musste zur Übernahme zwingen ?(
Einzig komisch findich deine Bindung - du bindest an .Current, wo ich an die BindingSource selbst gebündet hätte:
//Databinding auf Steuerelemente
textBoxVorname.DataBindings.Add("Text", m_bindingsource, "Vorname");
.Current ruft das Binding doch selber ab.
Der frühe Apfel fängt den Wurm.
Meiner übernimmt IMMER die Änderungen .. erst wenn ich eigene BeginEdit CancelEdit usw schreibe, habe ich auch die MÖglichkeit zum "Cancel"...
Wird jedoch eine MessageBox geöffnet, wird trotzdem EndEdit aufgerufen, obwohl ich es NICHT will .... (z.B. "Wollen Sie die Änderungen wirklich speichern?" -> User klickt auf Nein -> Änderungen werden trotzdem übernommen... kotz)
m_bindingsource.Current ist bei mir schon korrekt, anders funktionierts nich.. (oder liegt irgendwo in der Datenbinding der fehler?)
m_bindingsource.Current ist bei mir schon korrekt, anders funktionierts nich..
Du hast die Zeile genau so probiert, ja?
Zum anneren:
Evtl. ist das Grundkonzept daneben: Ein EingabeForm, welches auf den Original-Daten arbeitet.
Ich hab ja eigentlich sone Theorie von "Input-Form-Pattern", daß ein InputForm die bisherigen Daten als Kopie übergeben bekommen sollte, um sie als (editierbaren) Default-Input zu präsentieren.
Nach Schließen eines solchen InputForms werden bei DialogResult.Ok die Daten explizit in die Orig-Daten einkopiert.
Da jetzt BindingSource.CancelEdit() zum Canceln zu verwenden ist auch mein erster Versuch.
Der frühe Apfel fängt den Wurm.
Ja das war auch meine ursprüngliche Idee, aber mir war's zu aufwendig ne Kopie zu erstellen. Habe jetzt aber über das Begin, End und CancelEdit eine solche Möglichkeit eingebaut und werde dies wohl auch so machen ...
Ich finds nur schade, dass es grundsätzlich nativ die Möglichkeit gibt, aber nicht so funktioniert, wie sie sollte (ich bin ja nicht der einzige mit dem Problem).