Brie
Brie

Reputation: 2359

Why is the ValidationRule base constructor required for the ValidationRule derived class to be called on LostFocus?

I am trying to understand why if I do not call the ValidationRule base constructor, like

public GrainWeightValidate() : base(ValidationStep.UpdatedValue, true) { }

then when the Validation rule should be called, upon LostFocus (using on a TextBox as shown below), the Validate function is not called at all when the TextBox does indeed lose focus. However, if I change UpdateSourceTrigger below to PropertyChanged, then GrainWeightValidate.Validate() is called, but infinitely until there is a stack overflow. Following is the relevant XAML:

<Viewbox Grid.Row="1" Grid.Column="4">
    <AdornerDecorator>
        <TextBox Name="GrainWeightTextBox" MinWidth="23">
            <TextBox.Text>
                <Binding RelativeSource="{RelativeSource Self}" Path="Text" UpdateSourceTrigger="LostFocus">
                    <Binding.ValidationRules>
                        <local:GrainWeightValidate/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
    </AdornerDecorator>
</Viewbox>

Upvotes: 0

Views: 110

Answers (1)

rducom
rducom

Reputation: 7320

You are running in a StackOverflowException because of the RelativeSource Self binding. Validation isn't the source of your error.

Here you are Binding the Text DependencyProperty (TextProperty) of the TextBox to the Text property of the same TextBox. The Text property in it's implementation just call the corresponding DependencyProperty:

So when losing focus on the TextBox, the Bindings updates, and it updates Text, which updates the TextProperty DependencyProperty, which update Text, which updates the TextProperty... etc. etc.

Removes the RelativeSource attribute, and make the Path="..." value target a valid property on your ViewModel.

If you don't use MVVM, then you can maybe trick the Binding like this :

    <TextBox Name="GrainWeightTextBox" MinWidth="23">
        <TextBox.Text>
            <Binding ElementName="GrainWeightTextBox" Path="Tag" UpdateSourceTrigger="LostFocus">
                <Binding.ValidationRules>
                    <local:GrainWeightValidate/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

And then, get your value in code behind by accessing the Tag property. It's really really really dirty, but it should work....

Upvotes: 1

Related Questions