Laden...

Refresh DataGridView

Erstellt von be4all vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.911 Views
B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren
Refresh DataGridView

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... 😦

5.299 Beiträge seit 2008
vor 15 Jahren

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.

1.433 Beiträge seit 2006
vor 15 Jahren

Vielleicht findest Du hier noch ein paar nützliche Tipps.

Grüsse
Daniel
Space Profile
Wer nicht fragt, der nicht gewinnt

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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()

Ok, werde ich mal versuchen. Habe aber noch zwei Fragen:

  1. Wieso nicht SaveChanges verwenden? Irgendwie muss ich die Daten ja in die DB bringen
  2. Ich übergebe ja das Objekt an meine Form, die Datenbindung ist ja automatisch dann vorhanden - Änderungen an dem Objekt wirken sich direkt auf die Datasource aus..

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..)

5.299 Beiträge seit 2008
vor 15 Jahren

Hi!

  1. 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.

  2. 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.

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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()

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 ..

5.299 Beiträge seit 2008
vor 15 Jahren

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.

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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?

5.299 Beiträge seit 2008
vor 15 Jahren

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.

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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...

5.299 Beiträge seit 2008
vor 15 Jahren

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.

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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?)

5.299 Beiträge seit 2008
vor 15 Jahren

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.

B
be4all Themenstarter:in
66 Beiträge seit 2008
vor 15 Jahren

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).