locked
Data validation when custom converter is involved RRS feed

  • Question

  • I try to validate the input to a TextBox.
    The TextBox.Text is bound to a custom class property (of the ViewModel) which expects a text formatted like "x.y.z" where letters are integers With max. 5 digits each.

    The Conversion is handled by a Converter implementing IValueConverter.CovertBack which Returns a (negative) ValidationResult Object in case of format error.

    The custom class also implements the IDataErrorInfo Interface.

    The problem is that none of the IDataErrorInfo properties are called upon.

    How to do this correct in cases where a custom converter is involved ?

    Monday, September 26, 2016 1:36 PM

Answers

  • Hi EuroEager,

    the question is more why you're using a custom converter? Why don't you just let the value come to your ViewModel and do the validation there with IDataErrorInfo, as you have it already?


    Thomas Claudius Huber

    My latest Pluralsight-courses:
    WPF and MVVM: Test Driven Development of ViewModels
    WPF and MVVM: Advanced Model Treatment
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth

    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com

    • Marked as answer by EuroEager Thursday, September 29, 2016 9:07 PM
    Monday, September 26, 2016 3:36 PM
  • I try to validate the input to a TextBox.
    The TextBox.Text is bound to a custom class property (of the ViewModel) which expects a text formatted like "x.y.z" where letters are integers With max. 5 digits each.

    The Conversion is handled by a Converter implementing IValueConverter.CovertBack which Returns a (negative) ValidationResult Object in case of format error.

    The custom class also implements the IDataErrorInfo Interface.

    The problem is that none of the IDataErrorInfo properties are called upon.

    How to do this correct in cases where a custom converter is involved ?

    EuroEager,

    Thank you for posing your question to this forum.  Please allow me to get right to the point of your question.

    You said that your Converter is returning a ValidationResult.  This is not how to properly use a convert in WPF.  Converter and validation are done at separate times during a binding.  Simply put, your conversion must return a value other than what you intend.  So in your case you would convert the raw value to a string, but never mind about whether or not it is formatted correctly.  That will be done via the IDataErrorInfo implementation.  The key is to have the following

    1. ValidatesOnDataErrors=true setting in your binding (see code example below).

    <TextBox Text="{Binding Path=YourProperty, Converter={StaticResource yourConverter}, ValidatesOnDataErrors=True}" />
    

    2. Your model must notify WPF that its property was changed or it will invoke the IDataErrorInfo methods only once.  To do this, make sure to properly implement the INotifyPropertyChanged interface too. 

    I skimmed the article you referenced and suggest that you look for a simpler article concerning how to implement the IDataErrorInfo and INotifyPropertyChanged interfaces before you continue.  Below is a link that may help you understand these aspect of WPF.

    https://tarundotnet.wordpress.com/2011/03/03/wpf-tutorial-how-to-use-idataerrorinfo-in-wpf/

    God bless.


    - Rashad Rivera www.omegusprime.com

    • Proposed as answer by Rashad Rivera Thursday, September 29, 2016 3:31 AM
    • Marked as answer by EuroEager Thursday, September 29, 2016 9:06 PM
    Thursday, September 29, 2016 3:31 AM
  • >>(Are you the same Magnus Montin ?)

    Yes, I am :)

    I don't know what you mean by confused but in general, when you have a view model, you would implement either the IDataErrorInfo or INotifyDataErrorInfo in the view model class. Validation rules are not that MVVM friendly.

    But please start a new thread if you have a new question and please remember to close this thread by marking all helpful posts as answer. I believe that your original question has been answered.

    • Marked as answer by EuroEager Thursday, September 29, 2016 9:07 PM
    Thursday, September 29, 2016 7:27 PM

All replies

  • Hi EuroEager,

    the question is more why you're using a custom converter? Why don't you just let the value come to your ViewModel and do the validation there with IDataErrorInfo, as you have it already?


    Thomas Claudius Huber

    My latest Pluralsight-courses:
    WPF and MVVM: Test Driven Development of ViewModels
    WPF and MVVM: Advanced Model Treatment
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth

    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com

    • Marked as answer by EuroEager Thursday, September 29, 2016 9:07 PM
    Monday, September 26, 2016 3:36 PM
  • Thanks
    I thought about this, but in my "training project" I thought I should stick to purity and I do not feel that converting data is really a ViewModel concern, I might be "wrong" though.

    In this project I want to be a purist just for the sake of learning and build up good (?) habits.
    Most purists will probably say that the ViewModel shall expose data in a way that the View may "digest" without assuming anything regarding how the view will be doing this.
    Of course, in simple cases, pragmatism is probably fastest and most productive, but, as I said, I want to learn the "proper" way.

    So I still would like an answer to my actual question.

    Monday, September 26, 2016 3:47 PM
  • Ok, I see your point of using the converter: For learning.

    But I would never do it this way. The ViewModel normally provides the data in the form like it is required by the view. So in your case - even and also especially as an MVVM-purist - I wouldn't go with a Converter.

    Also read this entry from Josh Smith: Thought: MVVM eliminates 99% of the need for ValueConverters

    But yes, there are other cases, like decimal-properties that are formatted in the view to support the right number of digits etc.

    But let's assume you just have the converter. (as mentioned, you don't need it :))

    There are four ways to use the Validation that comes with WPF:
    - Validation Rules (property of the Binding object)
    - Throw an Exception in the property setter and set ValidatesOnException to true on your Binding
    - Implement IDataErrorInfo and set ValidatesOnDataErrors to true on your Binding
    - Implement INotifyDataErrorInfo

    INotifyDataErrorInfo is the one that I would recommend today. It's available since .NET 4.5.

    The validation is triggered for all cases when/after the data binding writes the data back to the model. So this means in MVVM, the validation is triggered after you've changed for example a TextBox and the string is written back to the ViewModel. Only with INotifyDataErrorInfo you can also raise the ErrorsChanged-event to force the validation again.

    Now what you're doing is returning an ValidationResult-object from the Converter. That won't do anything. Instead you should create a ValidationRule to put your stuff in, if you want:

    http://stackoverflow.com/questions/6123880/how-to-handle-exception-in-value-converter-so-that-custom-error-message-can-be-d

    But then again, what is the point to do it this way and to not use your IDataErrorInfo implementation?

    Did I mention it already? I wouldn't use a converter in MVVM for this case. A converter is not the proper way here.

    But to answer your question: Validation does not happen in the Converter. It happens in the four things I've mentioned above: ValidationRules, Exceptions in the setters, IDataErrorInfo and INotifyDataErrorInfo


    Thomas Claudius Huber

    My latest Pluralsight-courses:
    Compiled Data Binding Fundamentals in UWP Using XAML
    WPF and MVVM: Test Driven Development of ViewModels
    WPF and MVVM: Advanced Model Treatment
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth
    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com



    Monday, September 26, 2016 4:33 PM
  • >>How to do this correct in cases where a custom converter is involved ?

    If you are implementing the IDataErrorInfo interface you should perform the validation in the view model class. A converter is used to convert a value between different types - not to validate data.

    Instead of using a converter you should validate the value in the setter of your source property or in the indexer of your view model:

        public class ViewModel : IDataErrorInfo, INotifyPropertyChanged
        {
            private string _sourceProperty;
            public string SourceProperty
            {
                get { return _sourceProperty; }
                set { _sourceProperty = value; NotifyPropertyChanged("SourceProperty"); }
            }
    
            public string Error
            {
                get { return null; }
            }
    
            public string this[string columnName]
            {
                get
                {
                    switch (columnName)
                    {
                        //perform your validation logic here:
                        case "SourceProperty":
                            if (_sourceProperty.Length != 5)
                                return "The length must be 5!";
                            break;
                    }
    
                    return string.Empty;
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void NotifyPropertyChanged(string propertyName = "")
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    

    Also remember to set the ValidatesOnDataErrors property of the binding to true:

    <TextBox Text="{Binding Path=SourceProperty, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>

    Please refer to my blog post for more information about data validation in WPF: https://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/

    Hope that helps.

    Please remember to close your threads by marking helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Monday, September 26, 2016 4:50 PM
  • Thanks Magnus

    This works fine regarding validation, would you mind adding in a "real" property (a model object) ?

    I know that there are 2 different views on this kind of problems and I also read Josh Smith's 99% article plus others with opposite view.

    Doesn't your (and I guess, Thomas Claudius) create a cluttered ViewModel ?
    Easy to wrongly access the SourceProperty or it's backing field etc.
    (e.g. ModelObject property setter must set the SourceProperty's backing field and notify the SourceProperty as changed for updating the GUI, vice versa, the SourceProperty setter must access the ModelObject's backing field etc. for not creating a loop), seems to me a lot of complications along.

    Once I heard that GUI is like a joke, if you have to explain it it's no fun.
    I believe ViewModels should also be intuitive.

    But, of course I will listen to people with lot more experience than me (nada for me regarding validation/conversion) :)

    Monday, September 26, 2016 7:48 PM
  • >>Doesn't your (and I guess, Thomas Claudius) create a cluttered ViewModel ?

    I am not sure what you mean by "cluttered" but a view model is supposed to act like a model for the view and provide all necessary stuff that the view may need to be able to work property in its context (WPF in this case). So the view model should implement the IDataErrorInfo interface and provide the validation logic. This is certainly its responsibility. As mentioned it is the not the responsibility of a converter to implement validation logic.

    >>Easy to wrongly access the SourceProperty or it's backing field etc.
     (e.g. ModelObject property setter must set the SourceProperty's backing field and notify the SourceProperty as changed for updating the GUI, vice versa, the SourceProperty setter must access the ModelObject's backing field etc. for not creating a loop), seems to me a lot of complications along.

    The view binds to a view model property that may set a property of a pure wrapped model object (that doesn't implement any WPF aware interfaces at all) and provide change notifications to the view. This is how the MVVM pattern works.

    Hope that helps.

    Please remember to close your threads by marking all helpful posts as answer and then start a new thread if you have a new question. Please don't ask several questions in the same thread.

    Tuesday, September 27, 2016 7:27 PM
  • I am confused by reading https://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/ which treats both System.Windows.Data.IValueConverter and System.Windows.Controls.ValidationRule as useful in this process

    (Are you the same Magnus Montin ?)

    Wednesday, September 28, 2016 6:37 PM
  • I try to validate the input to a TextBox.
    The TextBox.Text is bound to a custom class property (of the ViewModel) which expects a text formatted like "x.y.z" where letters are integers With max. 5 digits each.

    The Conversion is handled by a Converter implementing IValueConverter.CovertBack which Returns a (negative) ValidationResult Object in case of format error.

    The custom class also implements the IDataErrorInfo Interface.

    The problem is that none of the IDataErrorInfo properties are called upon.

    How to do this correct in cases where a custom converter is involved ?

    EuroEager,

    Thank you for posing your question to this forum.  Please allow me to get right to the point of your question.

    You said that your Converter is returning a ValidationResult.  This is not how to properly use a convert in WPF.  Converter and validation are done at separate times during a binding.  Simply put, your conversion must return a value other than what you intend.  So in your case you would convert the raw value to a string, but never mind about whether or not it is formatted correctly.  That will be done via the IDataErrorInfo implementation.  The key is to have the following

    1. ValidatesOnDataErrors=true setting in your binding (see code example below).

    <TextBox Text="{Binding Path=YourProperty, Converter={StaticResource yourConverter}, ValidatesOnDataErrors=True}" />
    

    2. Your model must notify WPF that its property was changed or it will invoke the IDataErrorInfo methods only once.  To do this, make sure to properly implement the INotifyPropertyChanged interface too. 

    I skimmed the article you referenced and suggest that you look for a simpler article concerning how to implement the IDataErrorInfo and INotifyPropertyChanged interfaces before you continue.  Below is a link that may help you understand these aspect of WPF.

    https://tarundotnet.wordpress.com/2011/03/03/wpf-tutorial-how-to-use-idataerrorinfo-in-wpf/

    God bless.


    - Rashad Rivera www.omegusprime.com

    • Proposed as answer by Rashad Rivera Thursday, September 29, 2016 3:31 AM
    • Marked as answer by EuroEager Thursday, September 29, 2016 9:06 PM
    Thursday, September 29, 2016 3:31 AM
  • >>(Are you the same Magnus Montin ?)

    Yes, I am :)

    I don't know what you mean by confused but in general, when you have a view model, you would implement either the IDataErrorInfo or INotifyDataErrorInfo in the view model class. Validation rules are not that MVVM friendly.

    But please start a new thread if you have a new question and please remember to close this thread by marking all helpful posts as answer. I believe that your original question has been answered.

    • Marked as answer by EuroEager Thursday, September 29, 2016 9:07 PM
    Thursday, September 29, 2016 7:27 PM
  • Thanks again Magnus

    I do realize now that the best place to do conversion and validation is VM indeeed.

    I tried with a combo of ValidationRule, IValueConverter and INotifyDataErrorInfo and ended up with a messy XAML and difficulties showing both ValidationResult content and VM validation errors in the same adorner etc.

    I have decided to go that route even if I dislike the idea of exposing the model property as a string. After all, perhaps I later want an additional view using the same VM, but showing the int properties x, y, z (which are properties of the model, see threadstart) separately.



    • Edited by EuroEager Thursday, September 29, 2016 9:06 PM
    Thursday, September 29, 2016 9:04 PM