Question

I am trying to validate the WPF form against an object. The validation fires when I type something in the textbox lose focus come back to the textbox and then erase whatever I have written. But if I just load the WPF application and tab off the textbox without writing and erasing anything from the textbox, then it is not fired.

Here is the Customer.cs class:

public class Customer : IDataErrorInfo
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public string Error
        {
            get { throw new NotImplementedException(); }
        }
        public string this[string columnName]
        {
            get
            {
                string result = null;

                if (columnName.Equals("FirstName"))
                {
                    if (String.IsNullOrEmpty(FirstName))
                    {
                        result = "FirstName cannot be null or empty"; 
                    }
                }
                else if (columnName.Equals("LastName"))
                {
                    if (String.IsNullOrEmpty(LastName))
                    {
                        result = "LastName cannot be null or empty"; 
                    }
                }
                return result;
            }
        }
    }

And here is the WPF code:

<TextBlock Grid.Row="1" Margin="10" Grid.Column="0">LastName</TextBlock>
<TextBox Style="{StaticResource textBoxStyle}" Name="txtLastName" Margin="10"
         VerticalAlignment="Top" Grid.Row="1" Grid.Column="1">
    <Binding Source="{StaticResource CustomerKey}" Path="LastName"
             ValidatesOnExceptions="True" ValidatesOnDataErrors="True"
             UpdateSourceTrigger="LostFocus"/>         
</TextBox>
Was it helpful?

Solution

If you're not adverse to putting a bit of logic in your code behind, you can handle the actual LostFocus event with something like this:

.xaml

<TextBox LostFocus="TextBox_LostFocus" ....

.xaml.cs

private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
     ((Control)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}

OTHER TIPS

Unfortunately this is by design. WPF validation only fires if the value in the control has changed.

Unbelievable, but true. So far, WPF validation is the big proverbial pain - it's terrible.

One of the things you can do, however, is get the binding expression from the control's property and manually invoke the validations. It sucks, but it works.

Take a look at the ValidatesOnTargetUpdated property of ValidationRule. It will validate when the data is first loaded. This is good if you're trying to catch empty or null fields.

You'd update your binding element like this:

<Binding 
    Source="{StaticResource CustomerKey}" 
    Path="LastName" 
    ValidatesOnExceptions="True" 
    ValidatesOnDataErrors="True" 
    UpdateSourceTrigger="LostFocus">
    <Binding.ValidationRules>
        <DataErrorValidationRule
            ValidatesOnTargetUpdated="True" />
    </Binding.ValidationRules>
</Binding>

I found out the best way for me to handle this was on the LostFocus event of the text box I do something like this

    private void dbaseNameTextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        if (string.IsNullOrWhiteSpace(dbaseNameTextBox.Text))
        {
            dbaseNameTextBox.Text = string.Empty;
        }
    }

Then it sees an error

I've gone through the same problem and found an ultra simple way to resolve this : in the Loaded event of your window, simply put txtLastName.Text = String.Empty. That's it!! Since the property of your object has changed (been set to an empty string), the validation's firing !

The follow code loops over all the controls and validates them. Not necessarily the preferred way but seems to work. It only does TextBlocks and TextBoxes but you can easily change it.

public static class PreValidation
{

    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }


    public static void Validate(DependencyObject depObj)
    {
        foreach(var c in FindVisualChildren<FrameworkElement>(depObj))
        {
            DependencyProperty p = null;

            if (c is TextBlock)
                p = TextBlock.TextProperty;
            else if (c is TextBox)
                p = TextBox.TextProperty;

            if (p != null && c.GetBindingExpression(p) != null) c.GetBindingExpression(p).UpdateSource();
        }

    }
}

Just call Validate on your window or control and it should pre-validate them for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top