2009-10-28 4 views
7

Wenn ich die automatische Aktualisierung einer Bindungsdatenquelle durch Setzen von DataSourceUpdateMode = Nie deaktivieren und dann eine Schaltfläche verwenden, um die gesamte Menge (mit binding.WriteValue) zu aktualisieren, tritt ein Problem - nämlich nur die erste Die Datenquelle des gebundenen Steuerelements wird aktualisiert. Alle anderen Steuerelemente werden auf die ursprünglichen Werte zurückgesetzt.Manuelle Datenbindung mit WriteValue

Dies ist, weil, wenn das aktuelle Objekt ändert (wie nach dem obigen WriteValue passiert), wenn ControlUpdateMode = OnPropertyChange, alle anderen Steuerelemente den Wert aus der Datenquelle neu lesen.

Was ist die Standardmethode zur Vermeidung dieses Problems?

Eine Möglichkeit besteht darin, eine Klasse von BindingSource abzuleiten und eine WriteAllValues-Methode hinzuzufügen. Diese Methode macht folgendes:

(1) für jede Bindungs, speichern Sie die ControlUpdateMode

(2) für jede Bindungs ​​gesetzt ControlUpdateMode = Nie

(3) für jede Bindungs, rufen die Writevalue Verfahren

(4) für jede Bindungs, Reset ControlUpdateMode zu dem gespeicherten Wert

(5) für jede Bindungs, wenn ControlUpdateMode = OnPropertyChange, wobei das Verfahren Readvalue nennen.

Können Sie irgendwelche Probleme dabei sehen?

Wenn Sie mit Ihren eigenen Klassen arbeiten, würde die Implementierung von IEditableObject das Problem lösen?

In einem anderen Steuerelement, an dem ich arbeite, implementiere ich meine eigene Bindung. Die Art, wie ich das Problem dadurch umgehen kann, ist mit dem folgenden Code. (Ich habe in das Nötigste gesagt, ich hoffe es folgen!):

Private Shared ControlDoingExplicitUpdate As MyCustomControl = Nothing 

Private Sub UpdateDataSourceFromControl(ByVal item As Object, ByVal propertyName As String, ByVal value As Object) 
    Dim p As PropertyDescriptor = Me.props(propertyName) 
    Try 
    ControlDoingExplicitUpdate = Me 
    p.SetValue(item, value) 
    Catch ex As Exception 
    Throw 
    Finally 
    ControlDoingExplicitUpdate = Nothing 
    End Try 
End Sub 

Private Sub DataBindingSource_CurrentItemChanged(ByVal sender As Object, ByVal e As System.EventArgs) 
    If (ControlDoingExplicitUpdate IsNot Nothing) AndAlso (ControlDoingExplicitUpdate IsNot Me) Then Exit Sub 
    Me.UpdateControlFromDataSource() 'Uses ReadValue 
End Sub 

Also, wenn UpdateDataSourceFromControl genannt wird, werden alle CurrentItemChanged Ereignisse werden für alle anderen Kontrollen im gleichen Binding aufgerufen werden. Da ControlDoingExplicitUpdate jedoch festgelegt ist, werden sie den Wert aus der Datenquelle nicht erneut einlesen, es sei denn, sie sind das Steuerelement, das die Aktualisierung durchgeführt hat. ControlDoingExplicitUpdate wird auf Nothing gesetzt, nachdem alle diese Ereignisse abgeschlossen wurden, sodass der normale Dienst wieder aufgenommen wird.

Ich hoffe, Sie können dies folgen, und - wieder - ich frage, können Sie irgendwelche Probleme mit diesem sehen?

Antwort

4

Ich hatte ähnliche Anforderungen für ein Formular. In meinem Fall wollte ich nur die Datenbindung für alle Steuerelemente des Formulars auftreten, wenn ich auf die Schaltfläche Speichern des Formulars geklickt habe.

Die beste Lösung, die ich fand, war, den DataSourceUpdateMode jeder Bindung auf OnValidation zu setzen und dann die AutoValidate-Eigenschaft des enthaltenen Formulars auf Disable zu setzen. Das verhindert Bindung, wie Sie Fokus zwischen Steuerelementen in dem Formular ändern. Klicken Sie dann im Click-Ereignis für meine Schaltfläche "Speichern" manuell auf die Eingabe meines Formulars. Wenn dies OK ist, rufen Sie die ValidateChildren-Methode des Formulars auf, um die Bindung auszulösen.

Diese Methode hat auch den Vorteil, dass Sie vollständige Kontrolle darüber haben, wie Sie Ihre Eingaben validieren. WinForms enthalten keine gute Möglichkeit, dies standardmäßig zu tun.

2

Ich glaube, ich vor kurzem auf Stackoverflow lesen, wo dies als eine Antwort gegeben wurde: Disable Two Way Databinding

public static class DataBindingUtils 
{ 
    public static void SuspendTwoWayBinding(BindingManagerBase bindingManager) 
    { 
     if(bindingManager == null) 
     { 
      throw new ArgumentNullException ("bindingManager"); 
     } 

     foreach(Binding b in bindingManager.Bindings) 
     { 
      b.DataSourceUpdateMode = DataSourceUpdateMode.Never; 
     } 
    } 

    public static void UpdateDataBoundObject(BindingManagerBase bindingManager) 
    { 
     if(bindingManager == null) 
     { 
      throw new ArgumentNullException ("bindingManager"); 
     } 

     foreach(Binding b in bindingManager.Bindings) 
     { 
      b.WriteValue(); 
     } 
    } 
}