locked
MVVM number input validation RRS feed

  • Question

  • I implemented the interface IDataErrorInfo (.NET 4) for validating user input. Thanks to this I'm able to verify minimum and maximum value. View Model therefore knows whether it is possible to continue with the next action (eg. start the calculation).

    Question is, how to tell View Model, whether it is valid own entry of number? (User input cannot be parse to number.) In this case, public string this[string columnName] is not fired (of course...).

    Is there any other possibility, except to drill down throw all controls like this?

    private bool IsValid(DependencyObject obj)
    {
    	return !Validation.GetHasError(obj) && LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>().All(IsValid);
    }

    Best regards

    Lukas

    Sunday, January 10, 2016 9:15 PM

Answers

  • If you have errors in the view that stop it persisting to the viewmodel, say conversion errors, then you would need to tell the viewmodel about them.

    You can see one way to do that in this:

    http://social.technet.microsoft.com/wiki/contents/articles/28597.aspx

            <ControlTemplate x:Key="AddingTriggers" TargetType="ContentControl">
                <ControlTemplate.Resources>
                    <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource ErrorToolTip}">
                        <Setter Property="HorizontalAlignment" Value="Left"/>
                    </Style>
    
                </ControlTemplate.Resources>
                <StackPanel>
                    <i:Interaction.Triggers>
                        <local:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
                            <e2c:EventToCommand   Command="{Binding ConversionErrorCommand, Mode=OneWay}"
                                                  EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
                                                  PassEventArgsToCommand="True" />
                        </local:RoutedEventTrigger>
                    </i:Interaction.Triggers>
                    <TextBlock Text="This would be some sort of a common header" Foreground="LightBlue" HorizontalAlignment="Right"/>
                    <ContentPresenter/> <!-- This allows you to put variable content "within" the control in XAML -->
                    <TextBlock Text="This would some sort of a common footer" Foreground="LightBlue"  HorizontalAlignment="Right"/>
                </StackPanel>
            </ControlTemplate>
        </Application.Resources>

    When you have an error raised or removed then an errorevent is raised.

    That is passed to the viewmodel using EventToCommand.

    That particular sample doesn't do much with it:

            // From Validation.Error routed Event
            private RelayCommand<PropertyError> conversionErrorCommand;
            public RelayCommand<PropertyError> ConversionErrorCommand
            {
                get
                {
                    return conversionErrorCommand
                        ?? (conversionErrorCommand = new RelayCommand<PropertyError>
                            (PropertyError =>
                            {
                                if (PropertyError.Added)
                                {
                                    TheResult=PropertyError.Error;
                                }
                                else
                                {
                                    TheResult = "OK";
                                }
                            }));
                }
            }

    This one does though:

    https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204

    That's pretty complicated, but basically the errors are added to validation failures which are raised from dataannotations on each model and presented back to the view.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Marked as answer by Lukas___ Thursday, January 14, 2016 7:23 AM
    Monday, January 11, 2016 12:24 PM

All replies

  • You won't be able to ever set an int property of the view model to a string value but you could implement a validation rule if you want to customize the error message that is displayed in the view when the conversion fails. Please refer to my blog post about data validation in WPF for more information about this: http://blog.magnusmontin.net/2013/08/26/data-validation-in-wpf/.

    But again, you won't be able to set a view model property of type int to a string value. The setter will never be called. So you cannot handle this case in the view model.

    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.

    Sunday, January 10, 2016 10:00 PM
  • If you have errors in the view that stop it persisting to the viewmodel, say conversion errors, then you would need to tell the viewmodel about them.

    You can see one way to do that in this:

    http://social.technet.microsoft.com/wiki/contents/articles/28597.aspx

            <ControlTemplate x:Key="AddingTriggers" TargetType="ContentControl">
                <ControlTemplate.Resources>
                    <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource ErrorToolTip}">
                        <Setter Property="HorizontalAlignment" Value="Left"/>
                    </Style>
    
                </ControlTemplate.Resources>
                <StackPanel>
                    <i:Interaction.Triggers>
                        <local:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
                            <e2c:EventToCommand   Command="{Binding ConversionErrorCommand, Mode=OneWay}"
                                                  EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
                                                  PassEventArgsToCommand="True" />
                        </local:RoutedEventTrigger>
                    </i:Interaction.Triggers>
                    <TextBlock Text="This would be some sort of a common header" Foreground="LightBlue" HorizontalAlignment="Right"/>
                    <ContentPresenter/> <!-- This allows you to put variable content "within" the control in XAML -->
                    <TextBlock Text="This would some sort of a common footer" Foreground="LightBlue"  HorizontalAlignment="Right"/>
                </StackPanel>
            </ControlTemplate>
        </Application.Resources>

    When you have an error raised or removed then an errorevent is raised.

    That is passed to the viewmodel using EventToCommand.

    That particular sample doesn't do much with it:

            // From Validation.Error routed Event
            private RelayCommand<PropertyError> conversionErrorCommand;
            public RelayCommand<PropertyError> ConversionErrorCommand
            {
                get
                {
                    return conversionErrorCommand
                        ?? (conversionErrorCommand = new RelayCommand<PropertyError>
                            (PropertyError =>
                            {
                                if (PropertyError.Added)
                                {
                                    TheResult=PropertyError.Error;
                                }
                                else
                                {
                                    TheResult = "OK";
                                }
                            }));
                }
            }

    This one does though:

    https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204

    That's pretty complicated, but basically the errors are added to validation failures which are raised from dataannotations on each model and presented back to the view.


    Hope that helps.

    Technet articles: WPF: Layout Lab; All my Technet Articles

    • Marked as answer by Lukas___ Thursday, January 14, 2016 7:23 AM
    Monday, January 11, 2016 12:24 PM
  • Thank you Andy,

    that's exactly what I was looking for.

    Thursday, January 14, 2016 7:25 AM