wake-up-neo.com

Gültigkeitsprüfung für gebundene Steuerelemente in WPF

Ich habe einen WPF-Dialog mit ein paar Textfeldern ... _. Textfelder sind an mein Geschäftsobjekt gebunden und mit WPF-Überprüfungsregeln verknüpft.

Das Problem ist, dass der Benutzer perfekt auf die Schaltfläche "OK" klicken und das Dialogfeld schließen kann, ohne die Daten tatsächlich in Textfelder einzugeben. Validierungsregeln werden nie ausgelöst, da der Benutzer nicht einmal versucht hat, die Informationen in Textfelder einzugeben.

Ist es möglich, Validierungsprüfungen zu erzwingen und festzustellen, ob einige Validierungsregeln verletzt werden?

Ich wäre in der Lage, dies zu tun, wenn der Benutzer versucht, das Dialogfeld zu schließen, und es ihm untersagt, dies zu tun, wenn Validierungsregeln verletzt werden.

Vielen Dank.

55
Valentin

Wir haben dieses Problem auch in unserer Bewerbung. Die Validierung wird nur ausgelöst, wenn Bindungen aktualisiert werden. Sie müssen sie daher manuell aktualisieren. Wir machen das im Fenster Loaded des Fensters:

public void Window_Loaded(object sender, RoutedEventArgs e)
{
    // we manually fire the bindings so we get the validation initially
    txtName.GetBindingExpression(TextBox.TextProperty).UpdateSource();
    txtCode.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}

Dadurch wird die Fehlervorlage (rote Umrandung) angezeigt und die Validation.HasError - Eigenschaft festgelegt, durch die der OK-Button deaktiviert wird:

<Button x:Name="btnOK" Content="OK" IsDefault="True" Click="btnOK_Click">
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="IsEnabled" Value="false" />
            <Style.Triggers>
                <!-- Require the controls to be valid in order to press OK -->
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding ElementName=txtName, Path=(Validation.HasError)}" Value="false" />
                        <Condition Binding="{Binding ElementName=txtCode, Path=(Validation.HasError)}" Value="false" />
                    </MultiDataTrigger.Conditions>
                    <Setter Property="IsEnabled" Value="true" />
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
59
Robert Macnee

In 3.5SP1/3.0SP2 haben sie der ValidationRule-Basis außerdem eine neue Eigenschaft hinzugefügt, nämlich ValidatesOnTargetUpdated = "True" . Dadurch wird die Validierung aufgerufen, sobald das Quellobjekt gebunden ist, und nicht nur, wenn das Zielsteuerelement aktualisiert wird. Das ist vielleicht nicht genau das, was Sie wollen, aber es ist nicht schlimm, zunächst alles zu sehen, was Sie reparieren müssen.

Funktioniert ungefähr so:

<TextBox.Text>
    <Binding Path="Amount" StringFormat="C">
        <Binding.ValidationRules>
            <validation:RequiredValidationRule 
                ErrorMessage="The pledge amount is required." 
                ValidatesOnTargetUpdated="True"  />
            <validation:IsNumericValidationRule 
                ErrorMessage="The pledge amount must be numeric." 
                ValidationStep="ConvertedProposedValue" 
                ValidatesOnTargetUpdated="True"  />
        </Binding.ValidationRules>
    </Binding>
</TextBox.Text>
67
Ken Smith

Hier ist eine alternative Möglichkeit, die nicht den Aufruf von "UpdateSource ()" oder "UpdateTarget ()" erfordert:

var binding = thingToValidate.GetBinding(propertyToValidate);
foreach (var rule in binding.ValidationRules)
{
    var value = thingToValidate.GetValue(propertyToValidate);
    var result = rule.Validate(value, CultureInfo.CurrentCulture);
    if (result.IsValid) 
         continue;
    var expr = BindingOperations.GetBindingExpression(thingToValidate, propertyToValidate);
    if (expr == null)  
        continue;
    var validationError = new ValidationError(rule, expr);
    validationError.ErrorContent = result.ErrorContent;
    Validation.MarkInvalid(expr, validationError);
}
1
ryan

Verwenden Sie die oben von Robert Macnee vorgeschlagene Methode. Zum Beispiel:

//force initial validation
foreach (FrameworkElement item in grid1.Children)
{
    if (item is TextBox)
    {
        TextBox txt = item as TextBox;
        txt.GetBindingExpression(TextBox.TextProperty).UpdateSource();
    }
}        

Stellen Sie jedoch sicher, dass die gebundenen Steuerelemente sichtbar sind, bevor dieser Code ausgeführt wird!

0
Alex Pollan

Nur für den Fall, dass jemand diese alte Frage findet und nach einer Antwort sucht, die den Kommentar von Monstieur zu den Richtlinien der Benutzeroberfläche behandelt, habe ich Folgendes getan:

Xaml

<TextBox.Text>
    <Binding Path="TextValue" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
            <local:RequiredFieldValidationRule>
                    <local:RequiredFieldValidationRule.IsRequiredField>
                    <local:BoolValue Value="{Binding Data.Required, Source={StaticResource proxy}}" />
                </local:RequiredFieldValidationRule.IsRequiredField>
                <local:RequiredFieldValidationRule.ValidationFailed>
                    <local:BoolValue Value="{Binding Data.HasValidationError, Mode=TwoWay, Source={StaticResource proxy}}" />
                </local:RequiredFieldValidationRule.ValidationFailed>
            </local:RequiredFieldValidationRule>
        </Binding.ValidationRules>
    </Binding>
</TextBox.Text>

RequiredFieldValidationRule:

public class RequiredFieldValidationRule : ValidationRule
{
    private BoolValue _isRequiredField;
    public BoolValue IsRequiredField
    {
        get { return _isRequiredField; }
        set { _isRequiredField = value; }
    }
    private BoolValue _validationFailed;
    public BoolValue ValidationFailed
    {
        get { return _validationFailed; }
        set { _validationFailed = value; }
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        ValidationFailed.Value = IsRequiredField.Value && (value == null || value.ToString().Length == 0);
        return new ValidationResult(!ValidationFailed.Value, ValidationFailed.Value ? "This field is mandatory" : null);
    }
}

In der Klasse, an die der Xaml bindet

private bool _hasValidationError;
public bool HasValidationError
{
    get { return _hasValidationError; }
    set { _hasValidationError = value; NotifyPropertyChanged(nameof(HasValidationError)); }
}


public void InitialisationMethod() // Or could be done in a constructor
{
    _hasValidationError = Required; // Required is a property indicating whether the field is mandatory or not
}

Ich verstecken dann meine Schaltfläche Speichern mit einer gebundenen Eigenschaft, wenn eines meiner Objekte HasValidationError = true hat.

Hoffe, das ist für jemanden hilfreich.

0
lukep