0

I have a TextBox, and I am using ValidationRule.

<TextBox ..>
    <TextBox.Text>
        <Binding
            Mode="TwoWay"
            Path="DataTextBox"
            UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <validations:TextBoxValidation />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Here is the validation rule:

public class TextBoxValidation: ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        return (string.IsNullOrEmpty(value as string)) ?
            new ValidationResult(false, "This textbox cannot be empty") :
            new ValidationResult(true, null);
    }
}

I have this property in my ViewModel:

private string? _DataTextBox = string.Empty; //by default, set it as empty.
public string? DataTextBox
{
    get => _DataTextBox;
    set { SetProperty(ref _DataTextBox, value); }
}

I noticed that when I type in my TextBox, e.g. ABCDEFG, and then delete all the text, the DataTextBox property in my view model bound to the Text property of my TextBox still has the value A.

This behavior appears only when using the ValidationRule.

Why is that and how to fix it?

thatguy
  • 21,059
  • 6
  • 30
  • 40
Polar
  • 3,327
  • 4
  • 42
  • 77

1 Answers1

0

For validation rules, you can specify when they are applied via the ValidationStep property. The default value is RawProposedValue which means:

Runs the ValidationRule before any conversion occurs.

This also means that the validation occurs before the value of the bound source property is updated. Consequently, if the validation rule fails, e.g. the text box is left empty, the value will not be transferred back, since it is invalid, resulting in the last valid value for the DataTextBox property not being overwritten (in your case a).

You can change this behavior by specifying a different validation step after updating the source:

  • UpdatedValue

    Runs the ValidationRule after the source is updated.

  • CommittedValue:

    Runs the ValidationRule after the value has been committed to the source.

Then the value is updated before the validation rule is checked.

<local:TextBoxValidation ValidationStep="UpdatedValue" />
<local:TextBoxValidation ValidationStep="CommittedValue" />
thatguy
  • 21,059
  • 6
  • 30
  • 40
  • I couldn't make it right. It fixed the issue in the bind data, however, the validation result is returning invalid even if there is a valid input in both `ValidationStep`. – Polar Jul 27 '22 at 11:39
  • No value is being pass into the ValidationRule in both ValidationStep. – Polar Jul 27 '22 at 11:41
  • @Bolomeo Sorry, you did not do anything wrong, it is a WPF quirk. For the other validation steps, the actual value is passed as `value`, but for these two, the `BindingExpression` is passed. You did not notice it since you cast with `as`, which will return `null` for `str`, because it is a different type than `string`. Check `value` instead. In order to get the actual value from the `BindingExpression`, please refer to [this question addressing the issue](https://stackoverflow.com/q/10342715/6181599). – thatguy Jul 27 '22 at 11:59
  • I see, well then. That Fixed it. – Polar Jul 27 '22 at 12:29