C# 实现 WPF 文本框验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19539492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:13:57  来源:igfitidea点击:

Implement Validation for WPF TextBoxes

c#wpfvalidationxamldata-binding

提问by user2889489

I have 3 TextBoxes (Id1,Nameand Salary). Idand Salaryshould contain integers and Nameshould only contain characters. I need validations for my TextBox, it should show errors as I enter wrong characters or integers. Also can this be done only in Xaml without codebehind? Please help me with the required code

我有 3 个文本框(Id1,NameSalary)。Id并且Salary应该包含整数并且Name应该只包含字符。我需要验证我的文本框,当我输入错误的字符或整数时,它应该显示错误。这也只能在没有代码隐藏的情况下在 Xaml 中完成吗?请帮我提供所需的代码

This is Xaml code:

这是 Xaml 代码:

<TextBox Name="tb1" HorizontalAlignment="Left" Height="20" Margin="60,10,0,0" TextWrapping="NoWrap" Text="{Binding SelectedItem.Id,ElementName=dgsample}" VerticalAlignment="Top" Width="100" />
<TextBox Name="tb2" HorizontalAlignment="Left" Height="20" Margin="60,60,0,0" TextWrapping="NoWrap" Text="{Binding SelectedItem.Name, ElementName=dgsample}" VerticalAlignment="Top" Width="100"/>
<TextBox Name="tb3" HorizontalAlignment="Left" Height="20" Margin="60,110,0,0" TextWrapping="NoWrap" Text="{Binding SelectedItem.Salary, ElementName=dgsample}" VerticalAlignment="Top" Width="100"/>

回答by saurabh.mridul

To get it done only with XAML you need to add Validation Rules for individual properties. But i would recommend you to go with code behind approach. In your code, define your specifications in properties setters and throw exceptions when ever it doesn't compliance to your specifications. And use error template to display your errors to user in UI. Your XAML will look like this

要仅使用 XAML 完成它,您需要为各个属性添加验证规则。但我建议您使用代码隐藏方法。在您的代码中,在属性设置器中定义您的规范,并在不符合您的规范时抛出异常。并使用错误模板在 UI 中向用户显示您的错误。您的 XAML 将如下所示

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <Style x:Key="CustomTextBoxTextStyle" TargetType="TextBox">
        <Setter Property="Foreground" Value="Green" />
        <Setter Property="MaxLength" Value="40" />
        <Setter Property="Width" Value="392" />
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Trigger.Setters>
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}"/>
                    <Setter Property="Background" Value="Red"/>
                </Trigger.Setters>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <TextBox Name="tb2" Height="30" Width="400"
             Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}" 
             Style="{StaticResource CustomTextBoxTextStyle}"/>
</Grid>

Code Behind:

背后的代码:

public partial class MainWindow : Window
{
    private ExampleViewModel m_ViewModel;
    public MainWindow()
    {
        InitializeComponent();
        m_ViewModel = new ExampleViewModel();
        DataContext = m_ViewModel;
    }
}


public class ExampleViewModel : INotifyPropertyChanged
{
    private string m_Name = "Type Here";
    public ExampleViewModel()
    {

    }

    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            if (String.IsNullOrEmpty(value))
            {
                throw new Exception("Name can not be empty.");
            }
            if (value.Length > 12)
            {
                throw new Exception("name can not be longer than 12 charectors");
            }
            if (m_Name != value)
            {
                m_Name = value;
                OnPropertyChanged("Name");
            }
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}

回答by Kumareshan

You can additionally implement IDataErrorInfoas follows in the view model. If you implement IDataErrorInfo, you can do the validation in that instead of the setter of a particular property, then whenever there is a error, return an error message so that the text box which has the error gets a red box around it, indicating an error.

您还可以IDataErrorInfo在视图模型中实现如下。如果你实现了IDataErrorInfo,你可以在那个而不是特定属性的setter中进行验证,然后每当出现错误时,返回一条错误消息,以便有错误的文本框在它周围出现一个红色框,表示错误.

class ViewModel : INotifyPropertyChanged, IDataErrorInfo
{
    private string m_Name = "Type Here";
    public ViewModel()
    {
    }

    public string Name
    {
        get
        {
            return m_Name;
        }
        set
        {
            if (m_Name != value)
            {
                m_Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public string Error
    {
        get { return "...."; }
    }

    /// <summary>
    /// Will be called for each and every property when ever its value is changed
    /// </summary>
    /// <param name="columnName">Name of the property whose value is changed</param>
    /// <returns></returns>
    public string this[string columnName]
    {
        get 
        {
            return Validate(columnName);
        }
    }

    private string Validate(string propertyName)
    {
        // Return error message if there is error on else return empty or null string
        string validationMessage = string.Empty;
        switch (propertyName)
        {
            case "Name": // property name
                // TODO: Check validiation condition
                validationMessage = "Error";
                break;
        }

        return validationMessage;
    }
}

And you have to set ValidatesOnDataErrors=Truein the XAML in order to invoke the methods of IDataErrorInfoas follows:

并且您必须ValidatesOnDataErrors=True在 XAML 中进行设置才能调用IDataErrorInfo如下方法:

<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />

回答by Mr.B

There a 3 ways to implement validation:

有 3 种实现验证的方法:

  1. Validation Rule
  2. Implementation of INotifyDataErrorInfo
  3. Implementation of IDataErrorInfo
  1. 验证规则
  2. INotifyDataErrorInfo 的实现
  3. IDataErrorInfo 的实现

Validation rule example:

验证规则示例

public class NumericValidationRule : ValidationRule
{
    public Type ValidationType { get; set; }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string strValue = Convert.ToString(value);

        if (string.IsNullOrEmpty(strValue))
            return new ValidationResult(false, $"Value cannot be coverted to string.");
        bool canConvert = false;
        switch (ValidationType.Name)
        {

            case "Boolean":
                bool boolVal = false;
                canConvert = bool.TryParse(strValue, out boolVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of boolean");
            case "Int32":
                int intVal = 0;
                canConvert = int.TryParse(strValue, out intVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Int32");
            case "Double":
                double doubleVal = 0;
                canConvert = double.TryParse(strValue, out doubleVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Double");
            case "Int64":
                long longVal = 0;
                canConvert = long.TryParse(strValue, out longVal);
                return canConvert ? new ValidationResult(true, null) : new ValidationResult(false, $"Input should be type of Int64");
            default:
                throw new InvalidCastException($"{ValidationType.Name} is not supported");
        }
    }
}

XAML:

XAML:

Very important: don't forget to set ValidatesOnTargetUpdated="True"it won't work without this definition.

非常重要:不要忘记设置 ValidatesOnTargetUpdated="True"它没有这个定义将无法工作。

 <TextBox x:Name="Int32Holder"
         IsReadOnly="{Binding IsChecked,ElementName=CheckBoxEditModeController,Converter={converters:BooleanInvertConverter}}"
         Style="{StaticResource ValidationAwareTextBoxStyle}"
         VerticalAlignment="Center">
    <!--Text="{Binding Converter={cnv:TypeConverter}, ConverterParameter='Int32', Path=ValueToEdit.Value, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"-->
    <TextBox.Text>
        <Binding Path="Name"
                 Mode="TwoWay"
                 UpdateSourceTrigger="PropertyChanged"
                 Converter="{cnv:TypeConverter}"
                 ConverterParameter="Int32"
                 ValidatesOnNotifyDataErrors="True"
                 ValidatesOnDataErrors="True"
                 NotifyOnValidationError="True">
            <Binding.ValidationRules>
                <validationRules:NumericValidationRule ValidationType="{x:Type system:Int32}"
                                                       ValidatesOnTargetUpdated="True" />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
    <!--NumericValidationRule-->
</TextBox>

INotifyDataErrorInfo example:

INotifyDataErrorInfo 示例

public abstract class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        ValidateAsync();
    }
    #endregion


    public virtual void OnLoaded()
    {
    }

    #region INotifyDataErrorInfo
    private ConcurrentDictionary<string, List<string>> _errors = new ConcurrentDictionary<string, List<string>>();

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public void OnErrorsChanged(string propertyName)
    {
        var handler = ErrorsChanged;
        if (handler != null)
            handler(this, new DataErrorsChangedEventArgs(propertyName));
    }

    public IEnumerable GetErrors(string propertyName)
    {
        List<string> errorsForName;
        _errors.TryGetValue(propertyName, out errorsForName);
        return errorsForName;
    }

    public bool HasErrors
    {
        get { return _errors.Any(kv => kv.Value != null && kv.Value.Count > 0); }
    }

    public Task ValidateAsync()
    {
        return Task.Run(() => Validate());
    }

    private object _lock = new object();
    public void Validate()
    {
        lock (_lock)
        {
            var validationContext = new ValidationContext(this, null, null);
            var validationResults = new List<ValidationResult>();
            Validator.TryValidateObject(this, validationContext, validationResults, true);

            foreach (var kv in _errors.ToList())
            {
                if (validationResults.All(r => r.MemberNames.All(m => m != kv.Key)))
                {
                    List<string> outLi;
                    _errors.TryRemove(kv.Key, out outLi);
                    OnErrorsChanged(kv.Key);
                }
            }

            var q = from r in validationResults
                    from m in r.MemberNames
                    group r by m into g
                    select g;

            foreach (var prop in q)
            {
                var messages = prop.Select(r => r.ErrorMessage).ToList();

                if (_errors.ContainsKey(prop.Key))
                {
                    List<string> outLi;
                    _errors.TryRemove(prop.Key, out outLi);
                }
                _errors.TryAdd(prop.Key, messages);
                OnErrorsChanged(prop.Key);
            }
        }
    }
    #endregion

}

View Model Implementation:

查看模型实现:

public class MainFeedViewModel : BaseViewModel//, IDataErrorInfo
{
    private ObservableCollection<FeedItemViewModel> _feedItems;
    [XmlIgnore]
    public ObservableCollection<FeedItemViewModel> FeedItems
    {
        get
        {
            return _feedItems;
        }
        set
        {
            _feedItems = value;
            OnPropertyChanged("FeedItems");
        }
    }
    [XmlIgnore]
    public ObservableCollection<FeedItemViewModel> FilteredFeedItems
    {
        get
        {
            if (SearchText == null) return _feedItems;

            return new ObservableCollection<FeedItemViewModel>(_feedItems.Where(x => x.Title.ToUpper().Contains(SearchText.ToUpper())));
        }
    }

    private string _title;
    [Required]
    [StringLength(20)]
    //[CustomNameValidationRegularExpression(5, 20)]
    [CustomNameValidationAttribute(3, 20)]
    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            OnPropertyChanged("Title");
        }
    }
    private string _url;
    [Required]
    [StringLength(200)]
    [Url]
    //[CustomValidation(typeof(MainFeedViewModel), "UrlValidation")]
    /// <summary>
    /// Validation of URL should be with custom method like the one that implemented below, or with 
    /// </summary>
    public string Url
    {
        get { return _url; }
        set
        {
            _url = value;
            OnPropertyChanged("Url");
        }
    }

    public MainFeedViewModel(string url, string title)
    {
        Title = title;
        Url = url;
    }
    /// <summary>
    /// 
    /// </summary>
    public MainFeedViewModel()
    {

    }
    public MainFeedViewModel(ObservableCollection<FeedItemViewModel> feeds)
    {
        _feedItems = feeds;
    }


    private string _searchText;
    [XmlIgnore]
    public string SearchText
    {
        get { return _searchText; }
        set
        {
            _searchText = value;

            OnPropertyChanged("SearchText");
            OnPropertyChanged("FilteredFeedItems");
        }
    }

    #region Data validation local
    /// <summary>
    /// Custom URL validation method
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public static ValidationResult UrlValidation(object obj, ValidationContext context)
    {
        var vm = (MainFeedViewModel)context.ObjectInstance;
        if (!Uri.IsWellFormedUriString(vm.Url, UriKind.Absolute))
        {
            return new ValidationResult("URL should be in valid format", new List<string> { "Url" });
        }
        return ValidationResult.Success;
    }

    #endregion
}

XAML:

XAML:

<UserControl x:Class="RssReaderTool.Views.AddNewFeedDialogView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="300">
    <FrameworkElement.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Validation.ErrorTemplate">
                <Setter.Value>
                    <ControlTemplate x:Name="TextErrorTemplate">
                        <DockPanel LastChildFill="True">
                            <AdornedElementPlaceholder>
                                <Border BorderBrush="Red"
                                        BorderThickness="2" />
                            </AdornedElementPlaceholder>
                            <TextBlock FontSize="20"
                                       Foreground="Red">*?*</TextBlock>
                        </DockPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="Validation.HasError"
                         Value="True">
                    <Setter Property="ToolTip"
                            Value="{Binding RelativeSource=
            {x:Static RelativeSource.Self},
            Path=(Validation.Errors)[0].ErrorContent}"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
        <!--<Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError"
                         Value="true">
                    <Setter Property="ToolTip"
                            Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}" />
                </Trigger>
            </Style.Triggers>
        </Style>-->
    </FrameworkElement.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="5" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="5" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="5" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Text="Feed Name"
                   ToolTip="Display" />
        <TextBox Text="{Binding MainFeedViewModel.Title,UpdateSourceTrigger=PropertyChanged,ValidatesOnNotifyDataErrors=True,ValidatesOnDataErrors=True}"
                 Grid.Column="2" />

        <TextBlock Text="Feed Url"
                   Grid.Row="2" />
        <TextBox Text="{Binding MainFeedViewModel.Url,UpdateSourceTrigger=PropertyChanged,ValidatesOnNotifyDataErrors=True,ValidatesOnDataErrors=True}"
                 Grid.Column="2"
                 Grid.Row="2" />
    </Grid>
</UserControl>

IDataErrorInfo:

IDataErrorInfo:

View Model:

查看型号:

public class OperationViewModel : ViewModelBase, IDataErrorInfo
{
    private const int ConstCodeMinValue = 1;
    private readonly IEventAggregator _eventAggregator;
    private OperationInfoDefinition _operation;
    private readonly IEntityFilterer _contextFilterer;
    private OperationDescriptionViewModel _description;

    public long Code
    {
        get { return _operation.Code; }
        set
        {
            if (SetProperty(value, _operation.Code, o => _operation.Code = o))
            {
                UpdateDescription();
            }
        }
    }

    public string Description
    {
        get { return _operation.Description; }
        set
        {
            if (SetProperty(value, _operation.Description, o => _operation.Description = o))
            {
                UpdateDescription();
            }
        }
    }

    public string FriendlyName
    {
        get { return _operation.FriendlyName; }
        set
        {
            if (SetProperty(value, _operation.FriendlyName, o => _operation.FriendlyName = o))
            {
                UpdateDescription();
            }
        }
    }

    public int Timeout
    {
        get { return _operation.Timeout; }
        set
        {
            if (SetProperty(value, _operation.Timeout, o => _operation.Timeout = o))
            {
                UpdateDescription();
            }
        }
    }

    public string Category
    {
        get { return _operation.Category; }
        set
        {
            if (SetProperty(value, _operation.Category, o => _operation.Category = o))
            {
                UpdateDescription();
            }
        }
    }

    public bool IsManual
    {
        get { return _operation.IsManual; }
        set
        {
            if (SetProperty(value, _operation.IsManual, o => _operation.IsManual = o))
            {
                UpdateDescription();
            }
        }
    }


    void UpdateDescription()
    {
        //some code
    }




    #region Validation




    #region IDataErrorInfo

    public ValidationResult Validate()
    {
        return ValidationService.Instance.ValidateNumber(Code, ConstCodeMinValue, long.MaxValue);
    }

    public string this[string columnName]
    {
        get
        {
            var validation = ValidationService.Instance.ValidateNumber(Code, ConstCodeMinValue, long.MaxValue);

            return validation.IsValid ? null : validation.ErrorContent.ToString();
        }
    }

    public string Error
    {
        get
        {
            var result = Validate();
            return result.IsValid ? null : result.ErrorContent.ToString();
        }
    }
    #endregion

    #endregion
}

XAML:

XAML:

<controls:NewDefinitionControl x:Class="DiagnosticsDashboard.EntityData.Operations.Views.NewOperationView"
                               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                               xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                               xmlns:views="clr-namespace:DiagnosticsDashboard.EntityData.Operations.Views"
                               xmlns:controls="clr-namespace:DiagnosticsDashboard.Core.Controls;assembly=DiagnosticsDashboard.Core"
                               xmlns:c="clr-namespace:DiagnosticsDashboard.Core.Validation;assembly=DiagnosticsDashboard.Core"
                               mc:Ignorable="d">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Label Grid.Column="0"
               Grid.Row="0"
               Margin="5">Code:</Label>
        <Label Grid.Column="0"
               Grid.Row="1"
               Margin="5">Description:</Label>
        <Label Grid.Column="0"
               Grid.Row="2"
               Margin="5">Category:</Label>
        <Label Grid.Column="0"
               Grid.Row="3"
               Margin="5">Friendly Name:</Label>
        <Label Grid.Column="0"
               Grid.Row="4"
               Margin="5">Timeout:</Label>
        <Label Grid.Column="0"
               Grid.Row="5"
               Margin="5">Is Manual:</Label>
        <TextBox Grid.Column="1"
                 Text="{Binding Code,UpdateSourceTrigger=PropertyChanged,ValidatesOnDataErrors=True}"
                 Grid.Row="0"
                 Margin="5"/>
        <TextBox Grid.Column="1"
                 Grid.Row="1"
                 Margin="5"
                 Text="{Binding Description}" />
        <TextBox Grid.Column="1"
                 Grid.Row="2"
                 Margin="5"
                 Text="{Binding Category}" />
        <TextBox Grid.Column="1"
                 Grid.Row="3"
                 Margin="5"
                 Text="{Binding FriendlyName}" />
        <TextBox Grid.Column="1"
                 Grid.Row="4"
                 Margin="5"
                 Text="{Binding Timeout}" />
        <CheckBox Grid.Column="1"
                  Grid.Row="5"
                  Margin="5"
                  IsChecked="{Binding IsManual}"
                  VerticalAlignment="Center" />


    </Grid>
</controls:NewDefinitionControl>

回答by Muhammad Mehdi

I have implemented this validation. But you would be used code behind. It is too much easy and simplest way.

我已经实现了这个验证。但是你会被用到代码后面。这是太容易和最简单的方法了。

XAML:For name Validtion only enter character from A-Z and a-z.

XAML:对于名称验证,仅输入来自 AZ 和 az 的字符。

<TextBox x:Name="first_name_texbox" PreviewTextInput="first_name_texbox_PreviewTextInput" >  </TextBox>

Code Behind.

背后的代码。

private void first_name_texbox_PreviewTextInput ( object sender, TextCompositionEventArgs e )
{
    Regex regex = new Regex ( "[^a-zA-Z]+" );
    if ( regex.IsMatch ( first_name_texbox.Text ) )
    {
        MessageBox.Show("Invalid Input !");
    }
}

For Salary and ID validation, replace regex constructor passed value with [0-9]+. It means you can only enter number from 1 to infinite.

对于薪水和 ID 验证,将 regex 构造函数传递的值替换为[0-9]+. 这意味着您只能输入从 1 到无限的数字。

You can also define length with [0-9]{1,4}. It means you can only enter less then or equal to 4 digit number. This baracket means {at least,How many number}. By doing this you can define range of numbers in textbox.

您还可以使用 定义长度[0-9]{1,4}。这意味着您只能输入小于或等于 4 位的数字。这个 baracket 的意思是{至少,多少个数字}。通过这样做,您可以在文本框中定义数字范围。

May it help to others.

愿它对其他人有所帮助。

XAML:

XAML:

Code Behind.

背后的代码。

private void salary_texbox_PreviewTextInput ( object sender, TextCompositionEventArgs e )
{
    Regex regex = new Regex ( "[^0-9]+" );
    if ( regex.IsMatch ( salary_texbox.Text ) )
    {
        MessageBox.Show("Invalid Input !");
    }
}

回答by DiSaSteR

When it comes to Muhammad Mehdi's answer, it is better to do:

当谈到穆罕默德迈赫迪的回答时,最好这样做:

private void salary_texbox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
     Regex regex = new Regex ( "[^0-9]+" );
     if(regex.IsMatch(e.Text))
     {
         MessageBox.Show("Error");
     }
}

Because when comparing with the TextCompositionEventArgs it gets also the last character, while with the textbox.Text it does not. With textbox, the error will show after next inserted character.

因为当与 TextCompositionEventArgs 比较时,它也会得到最后一个字符,而与 textbox.Text 相比,它不会。使用文本框,错误将在下一个插入字符后显示。

回答by Peter Huber

When it comes to DiSaSteR's answer, I noticed a different behavior. textBox.Text shows the text in the TextBox as it was before the user entered a new character, while e.Text shows the single character the user just entered. One challenge is that this character might not get appended to the end, but it will be inserted at the carret position:

当谈到 DiSaSteR 的回答时,我注意到了不同的行为。textBox.Text 显示用户输入新字符之前 TextBox 中的文本,而 e.Text 显示用户刚刚输入的单个字符。一个挑战是这个字符可能不会被附加到末尾,但它会被插入到插入符号位置:

private void salary_texbox_PreviewTextInput(object sender, TextCompositionEventArgs e){
  Regex regex = new Regex ( "[^0-9]+" );

  string text;
  if (textBox.CaretIndex==textBox.Text.Length) {
    text = textBox.Text + e.Text;
  } else {
    text = textBox.Text.Substring(0, textBox.CaretIndex)  + e.Text + textBox.Text.Substring(textBox.CaretIndex);
  }

  if(regex.IsMatch(text)){
      MessageBox.Show("Error");
  }
}