0

I am testing use of regular expression as attribute in my application, but it is simply not working.

public partial class MainWindow : Window
{
    [Required]
    [RegularExpression(@"^[\d]+")]
    public string number { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        number = "sometext";
    }
 }

No error is being thrown and number accepts anything without caring for RegularExpression attribute.

How can I make number only to accept what is mentioned in regex? Usually I do validate in setter, but have learnt recently about attribute and wish to use it.

Thanks.

  • 2
    `I am testing` how? Attributes do nothing by themselves. Are you using data binding? Did you add validation in your form or page? You didn't post any code that shows an attempt to validate anything, or any input whose contents need to be validated – Panagiotis Kanavos Dec 17 '21 at 09:32
  • Yes, I am using binding where number is bind to a textbox in WPF. But I can enter anything there and is accepted – a_constant_variable Dec 17 '21 at 09:48
  • You didn't post any relevant code or show any actual problem. We can't guess what your form and bindings look like. The code you posted doesn't trigger validation so the attribute isn't used. – Panagiotis Kanavos Dec 17 '21 at 10:07
  • The `RegularExpressionAttribute` you are trying to use is not triggered by WPF controls. Check it's documentation: Specifies that a data field value in ASP.NET Dynamic Data must match the specified // regular expression. – Zserbinator Dec 17 '21 at 11:35
  • https://stackoverflow.com/questions/1268552/how-do-i-get-a-textbox-to-only-accept-numeric-input-in-wpf – ASh Dec 17 '21 at 12:05

2 Answers2

0

Thanks for comments. I modified code with some information on this site. myTextbox is bind with number and am using validation attribute. But still this is accepting everything that I write in my textbox.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        myTextBox.DataContext = this;         
    }

    [Required]
    [AcceptNumberAttribute]
    public string number { get; set; }        
 }

public sealed class AcceptNumberAttribute : ValidationAttribute

{

    public override bool IsValid(object value)
    {
        return new RegularExpressionAttribute(@"^[\d]$").IsValid(Convert.ToString(value).Trim());
    }

}

0

Your binding source must implement the IDataErrorInfo interface. Then you can set the ValidatesOnDataErrors and NotifyOnValidationError propeties on the binding.

See a simplified example below.

A base class to handle property changes and validation.


internal abstract class ValidatedObservableBase : INotifyPropertyChanged, IDataErrorInfo
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string this[string columnName]
    {
        get
        {
            var results = new List<ValidationResult>();
            var valid = Validator.TryValidateProperty(GetType().GetProperty(columnName)?.GetValue(this), new ValidationContext(this) { MemberName = columnName }, results);

            return valid ? null : results[0].ErrorMessage;
        }
    }

    public string Error
    {
        get => null;
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

The model, derived from the above base class.


internal class Model : ValidatedObservableBase
{
    private string number;

    [Required(ErrorMessage = "Required error")]
    [RegularExpression(@"^[\d]+", ErrorMessage = "Regex error")]
    public string Number
    {
        get => number;
        set
        {
            number = value;
            OnPropertyChanged();
        }
    }
}

A simple view model to set as the window's DataContext.


internal class ViewModel
{
    public Model Model { get; set; } = new Model();
}

Lastly, the window.


<Window
    ...
    xmlns:local="clr-namespace:Demo"
    mc:Ignorable="d">
    <Window.DataContext>
        <local:ViewModel />
    </Window.DataContext>
    <StackPanel>
        <TextBox
            x:Name="TB"
            Margin="24,24,24,0"
            VerticalAlignment="Top"
            Text="{Binding Path=Model.Number, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True}" />
        <TextBlock
            Margin="24,4,24,24"
            Foreground="Red"
            Text="{Binding ElementName=TB, Path=(Validation.Errors)[0].ErrorContent}" />
    </StackPanel>
</Window>

demo

Kostas K.
  • 8,293
  • 2
  • 22
  • 28