Aufruf von UpdateData(False) in DoDataExchange



  • Ist es möglich einen Aufruf von UpdateData(FALSE) zu tätigen in der Methode DoDataExchange. Wenn diese über UpdateData(True) ausgelöst wurde.

    void MainWindow::DoDataExchange(CDataExchange* pDX)
    {
    base::DoDataExchange(pDX);

    UpdateData(FALSE);
    }

    dies führt zu einer nicht viel aussagenden Exception:

    ---
    Exception Thrown
    MyProg.exe has triggered a breakpoint
    ---


  • Mod

    Das ist unsinnig.

    DoDataExchange ruft selbst UpdateData auf.
    Defakto ist das ein rekursiver Aufruf, was durch interne Mechanismen in der MFC jedoch verhindert wird. Deshalb der ASSERT!

    Was hast Du vor?



  • Hallo.

    Ja so was habe ich mir schon gedacht. Ich habe eine Art Databinding programmiert.
    Ändere ich nun ein Feld in meinem Dialog (View) und rufe ich bei Anderung dieses Feldes UpdateData(TRUE) auf. Darauf hin speichere ich die Daten in meiner Datenklasse (Model) ab. Dies wiederum benachrichtigt über ein Event (eigene Klasse) dass sich die Daten im Model geändert haben. Defakto muss die View also der Dialog wieder aktualisiert werden, denn es können ja noch andere Textfelder an die "Property" im Model gebunden sein.

    Also:
    Daten werden im Dialogfeld geändert -> UpdateData(True) wird aufgerufen -> DoDataExchange wird ausgeführt -> Daten werden im Model gespeichert -> Model wirft Event das Daten sich geändert haben -> UpdateData(FALSE) sollte aufgerufen werden damit sich der Dialog akutualisert.


  • Mod

    Würde ich so nicht machen. UpdateData(true) liest alle Datenfelder aus.

    Kann meines Erachtens auch so nicht gehen. UpdateData(TRUE) liest alle Datenfelder aus, umgekehrt benachrichtigt es wieder alle Datenfelder... löst also x-Events aus...

    Wenn Du eine Änderung bekommst, bearbeite diese im entsprechenden Event Handler.



  • "Wenn Du eine Änderung bekommst, bearbeite diese im entsprechenden Event Handler."

    Welche Richtung meinst du?

    View->Model
    Also wenn ich eine Änderung mache in einem Textfeld oder auch z.B. einen Button drücke muss ich ja alle Felder auslesen, da ich nicht weiß welche Felder sich alle gändert haben.

    Model->View
    Auch hier weiß ich nicht welches Dialogfeld aktualisiert werden muss. Hier wird ein PropertyChanged Event geworfen und alle Felder die angebunden sind müssen aktualisiert werden.


  • Mod

    Klar weißt Du das.

    Du bekommst einen Event wenn eine ComboBox sich ändern oder ein Edit Control.
    CBN_SELCHANGE, EN_CHANGE...



  • Na klar weiß ich das.

    Und was mache ich dann? Wenn sich ein Control ändert möchte ich gerne die Daten von der View auslesen und zwar die Daten aller Controls.

    Dazu rufe ich UpdateData(TRUE) auf. Oder was sonst?



  • @booster ich denke du hast da einen Denkfehler. Der View ist nur ein Ansicht der Daten in deiner Datenklasse (Model). Also Werden dir im View auch nur die Werte Angezeigt die in der Datenklasse aktuell stehen. Wenn jetzt ein Wert eines Editfeldes geändert wird, warum Willst du dann alle Werte vom View zurücklesen, die andern müssen ja noch aktuell sein.
    Nach der Berechnung oder was auch immer du in der Datenklasse da machst, kannst du dann logischerweise den oder die Werte wieder in den View schieben um diese aktuell anzuzeigen.
    Also wenn du EN_CHANGE des Edit überlädst, dann machst du genau die eine Berechnung mit dem neuen Wert und schiebst das/die Ergebnisse in das/die entsprechenden in die Felder zurück.

    Gruß CTecS



  • Hallo CTecS

    Nein kein Denkfehler würde ich sagen.

    Ich programmiere mir ein Framework das mir erlaubt beliebige Felder (Propertys) aus meiner Datenklasse direkt an die Controls der View zu binden ohne irgendwelche Felder in der View selber.

    Ich habe nun ein Property in meiner Datenklasse die nennt sich MyInProperty.
    Diese Property habe ich nun mit einem Binding (gelöst über Makros) an zwei Controlls meiner View gebunden. Ändere ich nun den Wert eines Controlls wird direkt das Model informiert (wenn OnPropertyChanged gesetzt ist) und MyIntProperty wird aktualisiert. Dies wiederum informiert dann alle Controls die an dieses Property gebunden sind. Hier in dem Fall also zwei Controlls.
    Das eine ist zwar aktuell aber das andere noch nicht.

    Dies entspricht dem Verhalten eines WPF Projekts mit MVVM in c#



  • Dann frag ich mich aber warum du alle Felder zurücklesen willst, wenn sie doch schon an die Datenklasse gebunden sind und du doch eigentlich durch deine direkte Verbindung von Datenfeldern und View doch gar kein UpdateData() benötigst.

    Entweder ich versteh nicht was das ganze miteinander zu tun hast oder du musst das noch etwas besser Erklären oder hier findet sich ein Findiger mitleser der deine Frage beantworten kann.

    Des weiter schreibst du dann das nach der Berechnung alle Controlls die mit der Property verbunden sind Informiert werden, warum können die dann nicht die Werte in der View aktualisieren? Die Wissen doch das sie betroffen sind und das ihre Werte im View nun nicht mehr aktuell sind.

    Ich glaub ich stell mehr Fragen als dir Antworten zu geben, ob dir das nützt oder nicht kann ich nicht sagen, aber Vielleicht hilft es so deine Fragen zu beantworten 😉


  • Mod

    @CTecS: Sehe ich genauso!



  • @CTecS
    1. Wieso soll ich kein UpdateData benötigen. Also statt einem eigens angelegtem Feld in der View verbinde ich meine ID des Controls mit dem Property aus dem Model über das DDX_Text Makro.

    Um nun den Wert aus dem Control in das Property zu schreiben muss ich ja UpdateData aufrufen. Oder wie kann man das anders machen?

    2. Die Propertys wissen dass Sie betroffen sind. Die werfen eine PropertyChanged Event und informieren alle die sich an dem Event registiert haben.

    Aber:
    Mir war bisher nicht klar dass man einzelne Dialogfelder auch einzeln beschreiben kann.

    Mit:
    SetDlgItemText(nIDC, value);
    GetDlgItem(nIDC)->RedrawWindow();

    Das bring mich schon mal ein Stück weiter.


  • Mod

    Du kannst natürlich mit GetDlgItemText/Int etc und GetWindowText die Daten jederzeit auch holen.

    DoDataExchange macht intern nicht anderes... debugge doch hinein.



  • Hallo Martin

    DoDataExchange macht ja an sich gar nichts. Oder das ist ja die Methode in der ich meinen Code platzieren um die Daten auszutauschen. z.B. mit DDX_Text.

    Nehmen wir mal an: ich möchte die Änderungen erst dann in die Model Schicht schreiben wenn jemand einen Button drückt. Dann müßte ich ja jedes Control durch gehen und es auslesen.

    Und dass würde ich gerne mit meinem Framework umgehen. Sprich ich verbinde meine Property im Model mit der ID des Controlls über DDX Text.

    Dann gibt es verschiedene Trigger die bestimmen wann die Daten ausgetauscht werden.
    Explicit
    Bei Änderung
    Lost Focus

    Und in diesem Trigger wird / sollte dann nur noch UpdateData(True) aufgerufen werden

    Sobald sich eine Property im Model ändert wird ein Event geworfen und die Daten in der View müssen aktualisiert werden. Und das durch den Aufruf UpdateData(False).



  • So kann man das machen, muss man aber nicht. 😃

    Ich würde einfach die paar Steuerelemente ob das nun ein CEdit oder CCombobox oder was auch immer in einer für das elemt entsprechenden Klasse ableiten also dann als CMyEdit zum Beispiel und diese direkt mit den entsprechenden Variablen verbinden, also das Steuerelement aktalisiert seine Daten entsprechen dem geworfenen Event. So muss mann dann auch nicht die ganzen Sachen 2 mal Speichern und bekommt dann auch keine Probleme mit Dateninkostistenzen.

    Aber du kannst das natürlich auch mit DDX_ aufrufen oder Membervariablem oder halt SetDlgItemText und GetDlgItemText oder sonst wie machen, kommt immer drauf an wie groß das ganze werden wird.

    Es gibt immer viele Lösungen für ein Problem nur sind einige dann auch später mehr ein Klotz als eine Lösung und der Datenaustausch zwischen View und Membervariable kann man in einer einfachen Dialoganwednung mit paar Elementen durchaus benutzen, sollte aber eine Datenklasse dazu kommen die aktiv dann noch mit den Daten arbeitet, kann es schnell dazu kommen das man mehr Probleme hat als man sich wünscht und dann geht die sucherei los.

    Aber sei es drum wenn du das so machen willst, dann hast hast du doch eigentlich schon deine Lösung für dich fertig gebastelt. Der Datenaustausch sollte ja so gehen wie du das beschrieben hast.



  • Hallo CTecS

    Welche paar Steuerelemente? Ich möchte ein Framwork machen, bei der ich jede ich beliebige Property an jedes x-beliebige Controll binden kann. und hierbei auch n:n Beziehungen wenn es sein muss. Und hierbei dann so wenig wie möglich Schreibarbeit haben. Da ist ja ein Ableiten vom Control mehr hinderlich. Ein Klotz am Bein wie du so schön sagst.

    Kennst du WPF? Das ist das Grundprinzip auf das ich setze.


  • Mod

    Dann Verwende OnCmdMsg. Dort erreichen alle Änderungsnachrichten den Dialog. Ob Du nun einen Handler hast oder nicht.
    Irgendwo hinterlegst Du die Bindung des Controls und machst es eben selbst. Wie es in WPF auch eben festgelegt wird.

    DoDataExchange und austauschen aller Daten immer wenn ein Control sich ändert ist der falsche Ansatz.



  • "Dann Verwende OnCmdMsg"
    Aha. Ok. Mal anschauen, noch keine Ahnung was ich da machen muss.

    "Irgendwo hinterlegst Du die Bindung des Controls und machst es eben selbst."

    Ja das ist eine gute Idee. Irgendwo hinterlegen und es selber machen.
    Kann man das in die FAQs aufnehmen. Das ist sicher so manchen hilfreich 🙂

    Ok Spaß bei Seite aber so richtig hilft das nicht weiter.


  • Mod

    Habe mich vertan... es ist OnCommand.
    OnCmdMsg beeinflusst das Command Routing.

    Dann sag ich es anders. Im WPF hinterlegst Du auch Bindungen.

    Das wird in der MFC eben durch DoDataExchange gemacht. Wenn Dir das nicht reicht und Du was anderes (ein eigenes Frame Work willst) musst Du die Bindung Control -> Daten ja selbst vornehmen...

    Das meine ich.
    Was ist daran nicht hilfreich?
    Du willst was anderes als die MFC bietet: Mach es selbst!
    Auch das geht eben. Siehe WM_COMMAND OnCommand....



  • Was heißt wenn mir das nicht reicht.
    Ich nutze die Technik von MFC und schreibe Makros darum die mir es erlauben meine Propertys ohne eigenes Datenfeld in der View anzubinden.

    Und wie du sagst wird dass in MFC durch DataExchange gemacht. Also schriebe ich darum herum meine Makros.

    "Wenn Dir das nicht reicht und Du was anderes (ein eigenes Frame Work willst) musst Du die Bindung Control -> Daten ja selbst vornehmen... "

    "Du willst was anderes als die MFC bietet: Mach es selbst!
    Auch das geht eben. Siehe WM_COMMAND OnCommand...."

    Ok. Also das ist ja nun mal eine Antwort. Weiß zwar noch nicht wie und was aber ich schau mal.

    Warum wir nun ganz so viel Einträge produziert haben weiß ich nicht. Wüßte jetzt auch nicht wie ich meine Frage anders hätte formulieren sollen.

    Fragt man allgemein: "Wie mache ich ein Framework für MFC das über Databinding funktioniert", würde ich wohl die Antwort erhalten zeig erst mal was du hast und Frage gezielter.

    Frage ich erst dann wenn ich auf ein Problem stoße heißt es: Wieso machst du das so was hast du denn vor.

    Wie gesagt ich versuche ein Databinding zu machen mit MFC und kann hier nur die Techniken nutzen die ich kenne. Und das war bisher über DataExchange. Und da reicht mir dann nicht einfach nur die Antwort dann mache es halt selber. Das ist nicht hilfreich!


Anmelden zum Antworten