简体   繁体   中英

Bind custom class with Validation in WPF

I noticed that it is possible to bind variables of the type DateTime to a textbox in WPF. If I enter a wrong value it will not validate and show a red border.

How can I implement my own class, that I can bind to a textbox without having to bind to a property of the class? The Textbox should show a string and the class will validate the input.

Is this possible?

My current solution is this:

In the Model:

public string DefaultLanguageValue
        {
            get
            {
                return _defaultLanguageValue;
            }
            set
            {
                if (value != this._defaultLanguageValue)
                {
                    ValidateLanguage(value);
                    this._defaultLanguageValue = value;
                    NotifyPropertyChanged();
                }
            }
        }

        
        private void ValidateLanguage(string value)
        {
            string rx = "([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]{1,8})(-[a-zA-Z]{1,8})*";
            if (!Regex.IsMatch(value, rx))
            {
                throw new ArgumentException();
            }
        }

In the XAML:

<TextBox Text="{Binding TreeViewModel.Model.DefaultLanguageValue, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" BorderThickness="0" MinWidth="100"/>

It would be nice to have a Class that I can just bind like a String, Int or DateTime for examlpe. Any Ideas?

You could bind to the Tag property of the TextBox itself and validate using a ValidationRule :

public class DateValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        if (!DateTime.TryParse(value as string, out DateTime _))
            return new ValidationResult(false, "Invalid date...");

        return ValidationResult.ValidResult;
    }
}

XAML:

<TextBox>
    <TextBox.Text>
        <Binding Path="Tag" RelativeSource="{RelativeSource Self}"
                         UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:DateValidationRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

This doesn't require you to bind to a view model.

I finally tried the solution suggested by mm8.

The only issue I have now is that if one enters an invalid value into the textbox, it will not update the textbox when I programmatically change the value of the source after clicking a button.

I tried Validation after update, but this allows the user to save invalid values.

<TreeViewItem>
                        <TreeViewItem.Header>
                            <StackPanel Orientation="Horizontal">
                                <CheckBox x:Name="chkDefaultLanguage" IsChecked="{Binding TreeViewModel.TreeModel.DefaultLanguage, UpdateSourceTrigger=PropertyChanged}"/>
                                <TextBlock Text="DefaultLanguage: "  />
                                <TextBox BorderThickness="0" MinWidth="100">
                                    <TextBox.Text>
                                        <Binding Path="TreeViewModel.TreeModel.DefaultLanguageValue" UpdateSourceTrigger="PropertyChanged">
                                            <Binding.ValidationRules>
                                                <validationrules:LanguageCodeValidationRule/>
                                            </Binding.ValidationRules>
                                        </Binding>
                                    </TextBox.Text>
                                </TextBox>
                            </StackPanel>
                        </TreeViewItem.Header>
                    </TreeViewItem>
class LanguageCodeValidationRule : ValidationRule
    {
        
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            string rx = "([a-zA-Z]{2}|[iI]-[a-zA-Z]+|[xX]-[a-zA-Z]{1,8})(-[a-zA-Z]{1,8})*";
            if (!Regex.IsMatch(value.ToString(), rx))
            {
                return new ValidationResult(false, "Invalid Language Codee.");
            }  
            return ValidationResult.ValidResult;
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM