Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delayed Input Validation with WPF

I have the following scenario in my WPF application:

  1. The user enters a value in a text box.
  2. I start a background thread to go validate that value (Via a Web Service call).
    (98% of the time the input is valid.)
  3. The user leaves the text box and heads on to work on the next text box(s).
  4. The background thread returns and the results indicate that the input was invalid.
    It lets the view model know this via the firing of an event. (I am using Prism events and modules.)

I need a way for that event to let the TextBox know that there was a Validation error with the input it was given. (Remember that the focus is no longer in that control.)

I can think of all kinds of ways to "roll my own validation" stuff and get this done. But I would like to work within an existing validation framework in WPF.

Note: I am not sure if it is relevant, but I will need to be maintaining a list of "NeededValidations" that will all have to pass before I enable the Save button.

like image 340
Vaccano Avatar asked Jun 30 '26 02:06

Vaccano


1 Answers

Here are a couple of methods using IDataErrorInfo that you can try. They both rely on the fact that raising INotifyPropertyChanged notification will cause re-evaluation of binding validation.

There are two text boxes. One uses an async binding and assumes the web service call is synchronous. The second uses a synchronous binding and assumes the web service call is async.

Xaml

<Window.DataContext>
    <WpfValidationUpdate:ViewModel/>
</Window.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBox Margin="5" Grid.Row="0" Text="{Binding Text1, IsAsync=True, ValidatesOnDataErrors=True}"/>
    <TextBox Margin="5" Grid.Row="1" Text="{Binding Text2, ValidatesOnDataErrors=True}"/>
</Grid>

View model

public class ViewModel : IDataErrorInfo, INotifyPropertyChanged
{
    private string _text1;
    private string _text2;
    private bool _text1ValidationError;
    private bool _text2ValidationError;

    #region Implementation of IDataErrorInfo

    public string this[string columnName]
    {
        get
        {
            if(columnName == "Text1" && _text1ValidationError)
            {
                return "error";
            }

            if(columnName == "Text2" && _text2ValidationError)
            {
                return "error";
            }

            return string.Empty;
        }
    }

    public string Error
    {
        get
        {
            return string.Empty;
        }
    }

    public string Text1
    {
        get { return _text1; }
        set
        {
            _text1 = value;
            OnPropertyChanged("Text1");

            // Simulate web service synchronously taking a long time
            // Relies on async binding
            Thread.Sleep(2000);
            _text1ValidationError = true;

            OnPropertyChanged("Text1");
        }
    }

    public string Text2
    {
        get { return _text2; }
        set
        {
            _text2 = value;
            OnPropertyChanged("Text2");

            // Simulate web service asynchronously taking a long time
            // Doesn't rely on async binding
            Task.Factory.StartNew(ValidateText2);
        }
    }

    private void ValidateText2()
    {

        Thread.Sleep(2000);

        _text2ValidationError = true;
        OnPropertyChanged("Text2");
    }

    #endregion

    #region Implementation of INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if(handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion
}
like image 134
Phil Avatar answered Jul 02 '26 22:07

Phil



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!