PropertyChangedEvent... kommt zu spät... oder gar nicht


Hi,

neuer Tag, neues Problem ;)

Kurz:
Aus einer Datenbank wird ein Integer gelesen, welches ja nach Wert einen Radiobutton setzen soll.
Wird einer dieser Radiobuttons geklickt (checked) soll dieser das ändern des Wertes in der DB veranlassen.

Da das Binding so nicht an den Radiobutton gebunden werden kann, habe ich mir aus verschiedenen Quellen Code und Wissen zusammengetragen -> Das Formular bekommt eine Property und ein Event PropertyChanged Implements INotifyPropertyChanged.PropertyChanged.

Das binding wurd an diese Property gebunden.

Code:
    Public Property propTest() As Integer
        Get
            If rbAktion1.Checked = True Then
                Return -1
            ElseIf rbAktion2.Checked = True Then
                Return 0
            Else
                Return 2
            End If
        End Get
        Set(ByVal value As Integer)
            If value = -1 Then
                rbAktion1.Checked = True
            ElseIf value = 0 Then
                rbAktion2.Checked = True
            ElseIf value = 2 Then
                rbAktion3.Checked = True
            End If
        End Set
    End Property
Wird das Formular geladen und durch die Datensätze geblättert, funkltioniert alles wie es soll. Die jeweiligen Radiobutton werdn selektiert.

Umgekehrt ruft jeder Radiobutton eine Methode auf die RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name)) auslöst. (Ich schwöre, das hat 30 Minuten lang, bis ich die Version ins SourceSafe gepackt habe, funktioniert!!)

Jetzt passiert genau gar nichts!

Erst wenn das Formular geschlossen wird, greift das Event scheinbar und die Property (get) wird aufgerufen.

Application.DoEvents() hilft leider nicht.

Warum werden die Events verschluckt?


Gruß
André
 

ksk

Erfahrenes Mitglied

Spyke

Premium-User
Eventuell noch als Info da ich denke mal du die Bindung über den Designer gesetzt hast:

Setzte die Bindung im Quellcode selbst dann bekommst du ein Binding Objekt zurück welches ein Parse und ein Format Ereignis hat.
Über diese Ereignisse könntest du das Checked der Radio Buttons steuern und steuern welcher Int Wert zurück in deine Eigenschaft geschrieben werden soll.
Code:
Binding bind = radio.DataBindings.Add("Text", bindingSource,"MeinInt",true, DataSourceUpdateMode.OnPropertyChanged);
bind.Parse + = radioBind_Parse;
bind.Format += radioBind_Format;
(bissl ausm Kopf getippt)

Jeweils im EventArgs die Eigenschaft mit bool (für RadioButton) oder Int (für die Eigenschaft) dann setzen.
Code:
radioBind_Format(...)
{
   if (e.Value is bool && sender == radioBind)
   {
        if((bool)e.Value)
              e.Value =2;
   }
}

radioBind_Parse(...)
{
   if (e.Value is int && sender == radioBind)
   {
        if((int)e.Value == 2)
              e.Value =true;
        else
            e.Value=false;
   }
}
(so ungefähr, leicht vereinfacht)
 
@ksk:
Naja, so viel mehr relevantes gibt es da nicht.
oben in der Klasse:

Code:
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
dann gibt es noch:

Code:
    Protected Sub OnPropertyChanged(sender As Object, e As PropertyChangedEventArgs)
        RaiseEvent PropertyChanged(Me, e)
    End Sub
und was die Radiobuttons machen (ist für alles Radiobutton gleich):

Code:
    Private Sub rbAktion1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbAktion1.CheckedChanged
        OnPropertyChanged(sender, New PropertyChangedEventArgs("propTest"))
    End Sub
Habe es mitlerweile variiert, vorher wurde nur "propTest" weitergegeben. Das Ergebnis ist das Gleiche.

Den Text zu MS-INotifyPropertyChanged habe ich gelesen, hat mir allerdings nicht geholfen.
Inwieweit hier noch das subscripe zum Event notwendig ist, ist schwer zu beurteilen. Meiner Meinung nach gar nicht, da ja das Event beim schließen des Formular plötzlich auftaucht.

Habe mitlerweile einige Beispiele gefunden, die es auf diese Weise lösen.
1. Event deklarieren
2. Über die Controls eine Methode ansprechen die RaiseEvent xy auslöst
3. Eine Property die darauf reagiert

@Spyke:

Sieht vielversprechend aus, werde ich ausprobieren wenn ich das alte nicht wieder zum Laufen bekommen.
Wobei, ist es richtig die Radiobuttons da an "Text" anzubinden?
 
so,

I'm having a similar issue where my data bound fields are changing as expected, but the PropertyChanged event is not always being raised to my calling code. Sometimes it does, sometimes it doesn't.
Monday, July 23, 2007 3:13 AM
das Problem taucht oft auf, zu oft wie ich finde.

Allerdings habe ich eine Lösung gefunden die, BIS JETZT, funktioniert.
An der Stelle wo ich das Databinding durchführe, habe ich folgendes feststellen können:

Code:
Dim radioBinder = New Binding("propTest", bindingSource, "feld1")
funktioniert nicht...

Code:
Dim radioBinder = New Binding("propTest", bindingSource, "feld1", True, DataSourceUpdateMode.OnPropertyChanged)
funktioniert!
ABER: es muss sowohl das true als auch die Angabe für den UpdateMode vorhanden sein.

Wenn das jetzt weiterhin funktioniert und mir das jemand erklären kann, bin ich erstmal wieder zufrieden.

Danke Spyke und ksk


Gruß
André
 

ksk

Erfahrenes Mitglied
Im Link ist zu sehen das nach jeden StateChanged, das Binding neu gesetzt.
Bei dir ist nicht ersichtlich wie was wo angebunden wird, ausser die paar kopierten Zeilen oben und
der Vorschlag von Spyke wie man es sonst noch machen könnte.


Code:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
     if (PropertyChanged != null)
     {
         PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
     }
}

public string CustomerName
{
     get
     {
         return this.customerNameValue;
     }
     set
     {
         if (value != this.customerNameValue)
         {
             this.customerNameValue = value;
             NotifyPropertyChanged();
         }
     }
... ruf mal innerhalb deiner SET-Property am Ende, die Methode "NotifyPropertyChanged" erneut auf.
Soweit ich das noch in erinnerung habe sollte der neuer Zustand immer danach erneut angebunden werden.
Sonst zeige mal dein Code.

Lg
ksk
 
@ksk:

Die ausführliche Binding-Zeile ;) :

Code:
        Dim radioBinder = New Binding("propKTest", bindingSource, "feld1", False, DataSourceUpdateMode.OnPropertyChanged)
        Me.DataBindings.Add(radioBinder)
der Aufruf von PropertyChanged in der Property wäre meiner Meinung nach hier nicht sinnvoll.
Der Ablauf ist ja wie folgt: Die Datenreihe ändert sich (Position in der BindingSource wird geändert) -> BindingSource, da gebunden an Formularproperty "propTest" veranlasst das setzen.

Wenn ich hier der BindingSource mitteile, nach dem sie mir gesagt hat was jetzt anzuzeigen / zu setzen ist, dass sich was geändert hat, obwohl dem nicht so ist, erscheint mir nicht so sinnvoll.

Der andere Ablauf: RadioButton wird gechecked -> ruft seine checkedChange auf -> diese ruft onPropertyChanged auf wo das Event PropertyChanged ausgelöst wird. (geraiset... furchtbare Bezeichnung :D) -> die BindingSource bzw das Binding holt sich aus der Property die akutellen Werte.

Spykes Idee finde ich gut, scheitert bei mir daran dass das Binding die benötigten Methoden / Properties scheinbar nicht besitzt (im Code).

Bisher funktioniert das fehlerfrei.


Gruß
André
 

Spyke

Premium-User
"propKTest" ist falsch,
dort muss eine Eigenschaft des Controls, welches gebunden wird angegeben werden, in deinem Fall müsste es glaube "Checked" sein.

"propKTest"<-- muss eine Eigenschaft des Controls sein
"feld1" <-- muss eine Eigenschaft des gebundenen Objektes sein

Parse und Format sind Ereignisse die du bei dem Objekt Binding abonnieren kannst,
welches dir die DataBindings.Add Methode zurückliefert.
 
@Spyke:

"propKTest" ist falsch,
dort muss eine Eigenschaft des Controls, welches gebunden wird angegeben werden, in deinem Fall müsste es glaube "Checked" sein.
Ja, wenn ich das auf deine Weise gelöst hätte. Leider fehlen mir da, wie oben geschrieben, die beiden Methoden. Habe leider noch nicht herausgefunden wieso.

Diese Lösung arbeitet mit einer Property des Formulars, an die die BindingSource gebunden wird. Sie funktioniert ähnlich. (und vorallem funktioniert sie endlich.... da rüttel ich erstmal nicht mehr dran :p)

Gruß
André