Search code examples
wpfvalidationidataerrorinfo

Conditional data validation in wpf


I have 3 radio buttons and a text box. See the image for UI

When user selects 'Phone' radio button I should allow to enter only numbers in the textbox, similarly the other cases email and name. Email should be in correct format. and name should start with character. How to do this in wpf?


Solution

  • Please try the next:

    The TextBox code

     <TextBox x:Name="TextBoxWithValidation" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding Text, UpdateSourceTrigger=LostFocus, Mode=TwoWay,
                                NotifyOnValidationError=True, ValidatesOnDataErrors=True}">
            <Validation.ErrorTemplate>
                <ControlTemplate>
                    <DockPanel>
                        <Border BorderBrush="Red" BorderThickness="1">
                            <AdornedElementPlaceholder x:Name="ControlWithError"/>
                        </Border>
                        <ContentControl x:Name="ValidationSymbol" Margin="-10,0,0,0" Content="{Binding ElementName=ControlWithError, 
                        Path=AdornedElement.(Validation.Errors), Converter={wpfValidationIssueHelpAttempt:Errors2ValidationErrorContentConverter}, 
                        UpdateSourceTrigger=PropertyChanged}" ContentTemplate="{StaticResource CommonValidationSymbol}"/>
                    </DockPanel>
                </ControlTemplate>
            </Validation.ErrorTemplate>
        </TextBox>
    

    The converter code:

    public class Errors2ValidationErrorContentConverter : MarkupExtension, IValueConverter
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return this;
        }
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var errors = value as ReadOnlyCollection<ValidationError>;
            ValidationError error;
            if (errors == null || (error = errors.FirstOrDefault()) == null) return null;
            return error.ErrorContent.ToString();
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The validation symbol code(put this to the resource section):

           <DataTemplate x:Key="CommonValidationSymbol">
                <TextBlock Panel.ZIndex="1000" Foreground="Red" FontFamily="Segoe UI" FontWeight="Bold" 
                               Width="10"
                               FontSize="15" Background="#0000FF00" Text="!">
            <ToolTipService.ToolTip>
                <ToolTip x:Name="validationTooltip" Content="{Binding }" Placement="Right"/>
            </ToolTipService.ToolTip>
                </TextBlock>
            </DataTemplate>
    

    Here is my DataContext code

    public class MainViewModel:BaseObservableObject, IDataErrorInfo
    {
        private string _text;
        private string _error;
        private bool _isMailChecked;
        private bool _isNameChecked;
        private bool _isPhoneChecked;
    
        public virtual string Text
        {
            get { return _text; }
            set
            {
                _text = value;
                OnPropertyChanged(() => Text);
            }
        }
    
        public string this[string columnName]
        {
            get
            {
                if (columnName == "Text")
                {
                    if (string.IsNullOrEmpty(Text)) return string.Empty;
                    Error = string.Empty;
                    return GetValidationResult();
                }
                return String.Empty;
            }
        }
    
        private string GetValidationResult()
        {
            //define your logic here
            if (IsNameChecked)
            {
                Error = "name is wrong!";
            }
            if (IsMailChecked)
            {
                Error = "mail is wrong!";
            }
            if (IsPhoneChecked)
            {
                Error = "phone is wrong";
            }
    
            return Error;
        }
    
        public string Error
        {
            get { return _error; }
            private set
            {
                _error = value;
                OnPropertyChanged(() => Error);
            }
        }
    
        public bool IsNameChecked
        {
            get { return _isNameChecked; }
            set
            {
                _isNameChecked = value;
                OnPropertyChanged(() => IsNameChecked);
                if (value == false) return;
                IsMailChecked = false;
                IsPhoneChecked = false;
                Text = String.Empty;
            }
        }
    
        public bool IsMailChecked
        {
            get { return _isMailChecked; }
            set
            {
                _isMailChecked = value;
                OnPropertyChanged(() => IsMailChecked);
                if (value == false) return;
                IsNameChecked = false;
                IsPhoneChecked = false;
                Text = String.Empty;
            }
        }
    
        public bool IsPhoneChecked
        {
            get { return _isPhoneChecked; }
            set
            {
                _isPhoneChecked = value;
                OnPropertyChanged(() => IsPhoneChecked);
                if (value == false) return;
                IsMailChecked = false;
                IsNameChecked = false;
                Text = String.Empty;
            }
        }
    }
    

    Regards.