Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF MVVM Textbox Validation

Tags:

c#

.net

mvvm

wpf

xaml

I'm creating a WPF application using MVVM. I have a textbox, which is bound to a property in my ViewModel of type double with a default value of 0.0. If I now enter a text value (say, abc) in the textbox, upon losing focus, the textbox is highlighted indicating an incorrect value. However, the user can still go ahead and click on Submit to invoke a ViewModel command. As the Text property of the textbox is bound to a property of type double in the ViewModel, the ViewModel property contains the default value, 0.0, and I'm unable to find out the text entered by the user.

Therefore, I'm unable to figure out if the user has actually entered a value of 0 or if there has been an incorrect input. How can I perform this validation correctly? Should I bind it to a string property so that I can get the entered text, and try to parse it to a double value to see if the input is correct? Or is there a better way of doing this?

<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="{Binding DoubleProperty}" VerticalAlignment="Top" Width="120"/>
like image 444
Fahad Avatar asked Feb 19 '15 19:02

Fahad


2 Answers

You can attach a Validation Rule to the binding of the textbox that checks if the value is a valid double. This will prevent the user from being able to press the Submit button unless a valid value is entered thereby eliminating your need to check if the DoubleProperty value is valid or not upon submit because it will only be valid when the submit button is enabled. Here is a simple example:

<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.Text>
            <Binding Path="DoubleProperty">
                <Binding.ValidationRules>
                    <validationrules:NumberValidationRule/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

In the above example you need to define a class NumberValidationRule that inherits ValidationRule.

Here is a sample NumberValidationRule

public class NumberValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        double result = 0.0;
        bool canConvert = double.TryParse(value as string, out result);
        return new ValidationResult(canConvert, "Not a valid double");
    }
}

Once you add a validation rule the text box will raise an error on the text field if your ValidationRule class says its not a valid value.

To prevent the submit button from being enabled you can add a CanExecute event to it that checks if the wpf window is valid. Like so:

<Window.CommandBindings>
    <CommandBinding Command="ApplicationCommands.Save" CanExecute="Save_CanExecute" Executed="Save_Executed"/>
</Window.CommandBindings>

... The rest of your page

<Button Content="Save" HorizontalAlignment="Left" Margin="43,146,0,0" VerticalAlignment="Top" Width="75" Command="ApplicationCommands.Save"/>                            

and in the code behind

private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = IsValid(sender as DependencyObject);
    }

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

Here is a more detailed example:

Validation in WPF

like image 55
kmcnamee Avatar answered Sep 18 '22 11:09

kmcnamee


You can try following solution. Firstly you should declare DoubleProperty as Nullable:

    public double? DoubleProperty { get; set; }

Then create converter class implemented IValueConverter. It can looks like this:

 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double result;
        if(!double.TryParse((string)value, out result))
        {
            return null;
        }

        return result;
    }

Finally, you can use it:

    xmlns:converter="clr-namespace:[TestApplication]"

<Window.Resources>
    <converter:DoubleToStringConverter x:Key="doubleToStringConverter" />
</Window.Resources>

<TextBox HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="{Binding DoubleProperty, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource doubleToStringConverter}}" VerticalAlignment="Top" Width="120"/>

Now, if user typed wrong values - DoubleProperty will be null.

like image 37
Yuri Dorokhov Avatar answered Sep 19 '22 11:09

Yuri Dorokhov