Laden...

MVVM - Problem bei Databinding bei TextBox

Erstellt von oehrle vor 9 Jahren Letzter Beitrag vor 9 Jahren 4.096 Views
O
oehrle Themenstarter:in
461 Beiträge seit 2009
vor 9 Jahren
MVVM - Problem bei Databinding bei TextBox

Hallo, tu mir im Moment gerade schwer. Ich verwende MVVM, das zuerst auch soweit funktionierte. Ich öffne in meiner WPF-Anwendung ein Window, in dem per XAML die Controls bestückt sind. Die Bindings an den DataContext sind dort auch schon gesetzt. Die Klasse mit den Feldern die an die Controls gebunden sind hat eben die Schnittstelle INotifyPropertyChanged, und die IDataErrorInfo für Fehlermeldung.

Nun ist es so, das ein paar Felder der Klasse die an die Controls gebunden werden, den Datentyp mit dem "?" versehen bekommen, damit sie "NULL" sein dürfen. Das mache ich deswegen so, damit der User neue gültige Werte eintragen kann. Ansonsten wären ja Vorgabedaten drin, und das möchte ich nicht, der User muss dort neue Daten eingeben. Und das kann ich nur feststellen, wenn zuvor nichts eingegeben war. Deswegen die NULL-Fahigkeit.

Ich prüfen dann bei der Datenübernahme (erfolgt durch Button-Click), ob die NULL-fähigen Variablen gesetzt sind, ansonsten kommt Fehlermeldung (IDataErrorInfo).

Damit das aber nicht sofort anspricht wenn das WPF-Window geöffnet wird, löse ich von diesen Controls das DataBinding und reagiere beim Button-Click der Datenübernahme mit der neuen Zuordnung der DataBindings für diese Controls. Es handelt sich um TextBoxen.

Hier mal der Code:


  //// Binding der TextBoxen entfernen, damit keine Fehlermeldung kommt, wenn Window aufgebaut wird
            BindingOperations.ClearBinding(tbx_Kantenradius, TextBox.TextProperty);
            BindingOperations.ClearBinding(tbx_Winkel1, TextBox.TextProperty);
            BindingOperations.ClearBinding(tbx_Breite1, TextBox.TextProperty);

Hier mal der Vorgang für die erste TextBox, wenn über Button die Eingabedaten übernommen werden sollen:


 btn_Datenübernahme.Click += (o, eventArgs) =>
                {
                    

                    DatenUebenehmenAktiv = true;

                        //// Binding wieder an Feld "Kantenradius" herstellen
                    Binding binding = new Binding("Kantenradius");
                    binding.NotifyOnSourceUpdated = true;
                    binding.NotifyOnTargetUpdated = true;
                
                    //// Test für Explizite Aktualisierung 
                    binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
                    binding.Mode = BindingMode.TwoWay;
               
                    binding.ValidatesOnDataErrors = true;
                    ////binding.NotifyOnValidationError = true;
                    ////binding.ValidatesOnExceptions = true;

                    //// Control wieder binden ==> Leider steht aber in tbx_Kantenradius.Text = ""  drin, obwohl etwas eingegeben wurde.
                    tbx_Kantenradius.SetBinding(TextBox.TextProperty, binding);
               
                    //// Explizite Aktualisierung lostreten    
                    tbx_Kantenradius.GetBindingExpression(TextBox.TextProperty).UpdateSource();
                

Wo mache ich den Fehler, das die Bindung nicht mehr funktioniert?

2.223 Beiträge seit 2005
vor 9 Jahren

Hallo oehrle,

warum machst du das ganze Binding im Code Behind ?

das kannst Du alles auch per XAML machen, dein Click Event wäre auch besser mit einem Command realisiert.

auch das mit dem Nullable, ist mir noch nicht besonders klar und macht in meinen Augen keinen Sinn.

Viele Grüße
Lars

2.207 Beiträge seit 2011
vor 9 Jahren

Ich verwende MVVM

Nein, das tust du nicht. Du hast immernoch CodeBehind bei dir. Dies wäre zu 99,999 % nicht vorhanden, wenn du MVVM richtig einsetzen würdest.

Ich stimme Lars Schmitt zu. Benutze Commands für deine Sachen und mach die bindings im XAML.

Weiter verstehe ich deine Frage nicht. Gibts überhaupt eine? Was ist denn nun das Problem?

Bitte beachte: [Hinweis] Wie poste ich richtig? Punkt 5

Gruss

Coffeebean

O
oehrle Themenstarter:in
461 Beiträge seit 2009
vor 9 Jahren

Sorry, Commands verwende ich hier nicht, wird auch noch ein Punkt werden. Zuerst aber das Problem mit dem BindingExpression. Das lösen der BindingExpresssion und erneute binden kann doch selbstverständlich immer wieder vorkommen. Habe das bei Galileo Computing gesehen (ziemlich unten Lissting 24.14 ist der Code):

Visual C# 2012 von Andreas Kühnel - Das umfassende Handbuch
Dort ist das Problem mit dem zufügen neuer Personen, bei mir ist das Problem, das manche Felder double-Werte enthalten die "nullfähig" sind, und deswegen mit "double ?" angelegt sind. Diese Felder müssen belegt werden und machen den Datensatz eindeutig (Pimarykeys), welche beim übernehmen der Daten über den Button sofoort in einer Datenbank das vorhandensein überprüft wird. Wenn ich bei den Feldern keine nullfähigkeit verwende, dann musss ich da sofort einen "Vorgabewert" einstellen oder es steht einfach "0" drin, was ich nicht möchte, und die Felder mit einer negativen Zahl belegen, das meine Prüfung erst mal so genehmigen würde geht nicht,weil die werte durchaus negativ sein können.
Meine Idee oder Vorgehen sieht so aus:

  1. User will einen neuen Datensatz zu einer bestimmeten Gruppe anlegen
  2. Mein System untersucht die Daten in DB und belegt ein paar definierte Felder vor, schreibt die in das Model (Klasse)
  3. Das Window mit dem Model wird geöffnet, diese Daten in den Textboxen angezeigt (dabei wird aber im Konstruktor nach Initialize() das Binding der drei TExtboxen aufgehoben).
  4. WIndow wird angezeigt, die drei Felder sind leer, es folgt kein roter Rahmen, wegen Fehler, da Bindung gelöscht ist.
  5. User hat Daten eingegeben und übernimmt per Buttonclick due Daten. Jetzt wird die BindingExpressiion der der drei Textboxen wieder gesetz, aber das Binnding funktioniert nicht!!! Warum ist die Frage?? Es kommen sofort die Fehlermeldungen zu den drei TExtboxen und die rote Umrahmung, obwohl gültige Werte in den Textboxen stehen.
    Gebe ich die Werte einzweites mal ein, funktionierts.

So, das nochmal zu meinem Problem. Habt ihr eine Idee an was es liegen könnte? UpdateSourceTrigger.Explizit setzen hatte ich auch schon bei einer TExtbox probiert. aber ohne Erfolg. Ich muss die Bindung irgenwie besser untersuchen können, was zuvor war und wie die neue Bindung ist.

2.223 Beiträge seit 2005
vor 9 Jahren

Hallo oehrle,

auch nach deiner Erklärung, macht dein Vorgehen keinen Sinn.

Ich vermute mal, dass Du deine Klasse entweder im Loaded Event vom Window oder nachdem dein Fenster angezeigt wird, an den DataContext vom Window übergibst.

Der Rote Rahmen, kommt Da deine Klasse für die Validation des jeweiligen Properties ein Fehler zurück gibt.

Wenn Du also beim initialen Anzeigen keinen Fehler angezeigt haben möchtest, warum baust Du deine Validation nicht so um, dass beim erstmaligen Anzeigen kein Fehler zurück gegeben wird.

zb. mit einem


private bool _isInitialized;  

und in der Validation prüfst Du dieses Field einfach mit ab

Viele Grüße
Lars

O
oehrle Themenstarter:in
461 Beiträge seit 2009
vor 9 Jahren

Ja, das Model wird im Konstruktor übergeben. Wie kann ich das mit dem ersten mal der Validierung einbauen? Muss ich das BindingExpression manipulieren?

2.223 Beiträge seit 2005
vor 9 Jahren

Das Field wird erst nach der Initialisierung oder zb. im Loaded Event auf true gesetzt

Viele Grüße
Lars

O
oehrle Themenstarter:in
461 Beiträge seit 2009
vor 9 Jahren

Hallo, Problem vorerst gelöst. Habe was gutes dazu gefunden, und dazu noch die Idee mit der boolschen Property. Hier habe ich auch was gutes für einen Tooltip gefunden (mittlerer Bereich in der Website):

Tooltip per code behind

Nur dazu noch etwas, wie kann ich im code behind den Tooltip mit ToolTipService ändern? das habe ich krampfhaft versucht und jetzt tut mir alles weh 😉. Tipp??

2.223 Beiträge seit 2005
vor 9 Jahren

Hallo oehrle,

auch dieses Problem kann ohne Code Behind realisiert werden

schau Dir doch mal die Thematik rund ums ErrorTemplate an

Validation.ErrorTemplate (angefügte Eigenschaft)

das ErrorTemplate kannst Du so anpassen, dass dein Fehler im ToolTip angezeigt wird.

Viele Grüße
Lars