0

I have a custom validation attribute for validating decimal properties

public sealed class DecimalAttribute : ValidationAttribute
{
    public DecimalAttribute()
    {
        this.ErrorMessage = "The input must be a decimal number";
    }

    private object Value { get; set; }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        this.Value = value;

        return base.IsValid(value, validationContext);
    }

    public override bool IsValid(object value)
    {
        if (this.Value == null) return false;

        decimal result;
        return decimal.TryParse(this.Value.ToString(), out result);
    }
}

However when it doesn't work and when I bind the textbox to that property and input an invalid value into the textbox the message "Value '' could not be converted" is displayed instead of the error message of the my custom validation attribute.

Interestingly, I've figure it out that the other validation attributes like "Required" does not work on the numeric properties either.

Edit

My bind part is:

    <TextBox>
        <TextBox.Text>
            <Binding Path="Price" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" NotifyOnValidationError="True">
                <Binding.ValidationRules>
                    <local:DecimalValidationRule />
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

My Solutuion

This is the way I've solved my problem. I'm not sure if its is the best way however I share it for any recommandations of yours.

I've actually used two properties, one for binding and validating and the other for saving data in the database

    [NotMapped, Decimal]
    public string PriceString
    {
        get { return _priceString; }
        set { if (SetValue(ref _priceString, value)) OnPropertyChanged("Price"); }
    }

    public decimal Price
    {
        get
        {
            decimal result;
            decimal.TryParse(this.PriceString, out result);
            return result;
        }
        set { PriceString = value.ToString(); }
    }

Now it works exactly what I need.

Please make your comments, give your recommendations and provide any better solutions please.

user3530012
  • 720
  • 2
  • 20
  • 37
  • 1
    my first thought is when you are entering any wrong value in textbox, even the setter of attached property is not getting called and that is because some internal logic of WPF is checking for validatin. Now, as custom validation is working on property changed and property is never changed , it is not working. Alternatives like binding textbox with string property and chaning it to int later or restrecting user to enter only numbers in textbox can help if you want. – Naresh Ravlani Sep 01 '15 at 03:29
  • @NareshRavlani I thinks its related to the default validation rule of the bindings in WPF. I've decided to use a string property instead and use this attribute to make the user enter only decimal numbers. – user3530012 Sep 01 '15 at 07:55
  • could you please show your bindpart – WiiMaxx Sep 01 '15 at 08:37
  • @WiiMaxx I've added my bindpart to the question. – user3530012 Sep 01 '15 at 08:54
  • 1
    add DecimalValidationRule – Nikita Shrivastava Sep 01 '15 at 09:16

2 Answers2

0

Add [AttributeUsage(AttributeTargets.Property)] above the class declaration.

[AttributeUsage(AttributeTargets.Property)] 
public sealed class DecimalAttribute : ValidationAttribute
Nikita Shrivastava
  • 2,978
  • 10
  • 20
  • I've done this but nothing changed. Strangely this behavior is only for numeric properties I suppose. My custom validation attributes always work for string properties. – user3530012 Sep 01 '15 at 08:17
  • I've noticed that binding a TextBox to a numeric property does not call the setter of that property when entering invalid character in the TextBox. How may I solve this problem? – user3530012 Sep 01 '15 at 08:28
0

you need to add your ValidationAttribute to your property

[DecimalAttribute] // <-- this part is missing
public decimal Price
    {
       // get set
    }

also you may need

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
WiiMaxx
  • 5,322
  • 8
  • 51
  • 89