8 Stimmen

Das Abbrechen des Validierungsereignisses eines datengebundenen Steuerelements unterdrückt nicht den Versuch, die Datenquelle zu aktualisieren

Ich erhalte nicht das Verhalten, das ich für eine TextBox erwarten würde, die an eine Integer-Eigenschaft in einem Business-Objekt gebunden ist.

Ich habe Folgendes getan:

(1) Stellen Sie die DataSourceUpdateMode für die TextBox zu: OnValidation .

(2) In der Validating Ereignis für die TextBox, setzen Sie e.Cancel = True wenn Integer.TryParse fehlschlägt.

(3) Fügen Sie einen Handler für Binding.Parse y Binding.BindingComplete und setzen Sie Haltepunkte in den Handlern.

Starten Sie die Anwendung, geben Sie "asdasd" in die TextBox ein und verlassen Sie die Anwendung mit der Tabulatortaste. Trotz Einstellung e.Cancel = True die Parse y BindingComplete Ereignisse werden beide ausgelöst. Der Dokumentation zufolge ist die Einstellung e.Cancel = True sollte jede weitere Logik unterdrücken.

Ich habe MSDN durchsucht, um herauszufinden, warum das passiert, aber ich kann nichts finden. Weiß jemand, wo ich einige Details zu diesem Thema finden kann?

ETA : Ich habe auch ein Handle für das Ereignis Validated hinzugefügt. Hier ist die Reihenfolge der Ereignisse:

Schlechte Daten:

(1) Validierung. (I eingestellt e.Cancel = True )

(2) Parsen

(3) BindingComplete

Gute Daten:

(1) Validierung

(2) Parsen

(3) BindingComplete

(4) Validiert

ETA2 : Weitere Informationen und eine Umgehungslösung.

Das Problem mit diesem Verhalten ist, wenn Sie einige Validierung, die nicht in der Eigenschaft Setter implementiert ist haben.

Nehmen wir zum Beispiel an, meine Integer-Eigenschaft muss eine ungerade Zahl sein. Ich überprüfe dies nicht im Property Setter, sondern erst im Validierungsereignis.

Wie Sie aus dem obigen Verhalten ersehen können, wird der Wert als legitime Ganzzahl in die Datenquelle geschrieben, auch wenn ich die Validierung abbreche.

Trotz der Tatsache, dass die Datenquelle aktualisiert wird, wird das Validated-Ereignis nicht ausgelöst, wenn Sie Cancel im Validating-Ereignis setzen, so dass Sie den Benutzer immer noch daran hindern können, weiterzugehen.

Work-Around::

Um die Aktualisierung der Datenquelle zu stoppen, müssen Sie in der Datei Binding.Parse Ereignis und löst eine Ausnahme aus, die verhindert, dass Binding erfolgreich abgeschlossen wird.

0 Stimmen

Guter Fund. [Sieht aus wie ein Winforms-Fehler][1]. [1]: connect.microsoft.com/VisualStudio/feedback/

0 Stimmen

Danke, ich habe den Fehler hochgestuft und ein Workaround hinzugefügt.

2voto

helgeheldre Punkte 1041

Das Hinzufügen eines Aufrufs zu CancelEdit scheint den Unterschied zu machen.

    private void textBox1_Validating(object sender, CancelEventArgs e)
    {
        bindingSource1.CancelEdit();
        e.Cancel = true;
    }

0 Stimmen

Beachten Sie, dass CancelEdit den Bindungswert in das Steuerelement einlesen wird. Dadurch wird die Änderung gelöscht, was eine gute Sache sein kann (wenn Sie keine Rückgängig-Funktion beim Drücken der ESC-Taste hinzufügen wollen) oder eine schlechte Sache, weil der Benutzer den gesamten Wert als Korrektur neu eingeben muss.

0voto

Nathan Punkte 678

Ich weiß, dies ist alt, aber ich habe zu viel Zeit damit verbracht, nach der gleichen Antwort zu suchen. Ich hoffe, dass dies jemand anderem auf seinem Weg hilft. CodeMag hat einen sehr guten Artikel über Object Binding, die helfen können.

Tipps und Tricks zur Objektbindung von CodeMag

Dies ist das Formular, das ich erstellt habe, um den von mir geschriebenen Code zu testen.

Test Form with no Errors

Dieses Bild zeigt, dass der Fehlerprovider die Ausnahme aufgreift und anzeigt, die ausgelöst wird, weil der Wert außerhalb des Bereichs liegt, den ich im Eigenschaftssetzer festgelegt habe.

Test Form with Errors

Der Schlüssel zum Abbrechen der Aktualisierung ist die Eingabe von e.Binding.BindingManagerBase.CancelCurrentEdit() im Ereignis "Bindungsquelle abgeschlossen".

Imports System.ComponentModel
Imports System.Runtime.CompilerServices

Public Class frmTest

Private WithEvents PersonBindingSource As New Person
Private WithEvents ErrorProvider1 As New ErrorProvider
Private WithEvents FirstNameBinding As Binding
Private WithEvents AgeBinding As Binding

Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    Me.ErrorProvider1.ContainerControl = Me
End Sub

Private Sub frmTest_Load(sender As Object, e As EventArgs) Handles Me.Load
    ErrorProvider1.DataSource = PersonBindingSource

    FirstNameBinding = TextBox1.DataBindings.Add("Text", PersonBindingSource, "FirstName", True, DataSourceUpdateMode.OnValidation)
    AgeBinding = TextBox2.DataBindings.Add("Text", PersonBindingSource, "Age", True, DataSourceUpdateMode.OnValidation)

End Sub

Private Sub FirstNameBinding_BindingComplete(sender As Object, e As BindingCompleteEventArgs) Handles FirstNameBinding.BindingComplete
    If Not e.BindingCompleteState = BindingCompleteState.Success Then
        e.Binding.BindingManagerBase.CancelCurrentEdit()
    End If
End Sub

Private Sub AgeBinding_BindingComplete(sender As Object, e As BindingCompleteEventArgs) Handles AgeBinding.BindingComplete
    If Not e.BindingCompleteState = BindingCompleteState.Success Then
        e.Binding.BindingManagerBase.CancelCurrentEdit()
    End If
End Sub

End Class

Öffentliche Klasse für Person

Public Class Person
Implements INotifyPropertyChanged

Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Protected Sub NotifyPropertyChanged(<CallerMemberName()> Optional ByVal propertyname As String = Nothing)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyname))
End Sub

Private _FirstName As String = "First Name"
Public Property FirstName() As String
    Get
        Return _FirstName
    End Get
    Set(ByVal value As String)
        If value.Length > 10 Then
            Throw New Exception("First name must be shorter than 10 characters")
        End If
        If (value <> _FirstName) Then
            _FirstName = value
            NotifyPropertyChanged()
        End If
    End Set
End Property

Private _Age As Decimal = 21
Public Property Age() As Decimal
    Get
        Return _Age
    End Get
    Set(ByVal value As Decimal)
        If value > 50 Then
            Throw New Exception("A person cannot be older than 50")
        ElseIf value < 21 Then
            Throw New Exception("A person cannot be younger than 21")
        ElseIf (value <> _Age) Then
            _Age = value
            NotifyPropertyChanged()
        End If
    End Set
End Property

End Class

EDIT。

Dies wurde mit Visual Studio 2013 mit .Net4.6 erstellt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X