Есть TextBox в которые пользотель вводит числа или буквы. Нужно проверить и при вводе букв допустим в "год" выдать ошибку.
- 6,384
- 31
- 1
- 3
2 Answers
Лучшее решение, я считаю, это использование прелестей MVVM и Binding. Первое, что нам следует - разделить вьюхи и логику их моделей. Второе - задать биндинг и реализовать INotifyPropertyChanged интерфейс, который нужен для оповещения вьюхи при изменении свойст на вью модели. Третье - реализовать интерфейс IDataErrorInfo нашей вьюмоделью.
Итого по итогу получаем следующее:
На вьюхе будут присутствовать элементы:
<TextBox Text="{Binding Year, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
<TextBlock Text="{Binding Error}" />
Где UpdateSourceTrigger служит для немедленного оповещения о изменении текста на TextBox элементе и ValidatesOnDataErrors - для включении валидации.
Сделаем два абстрактным базовых класса для упрощения:
ViewModelBase класс будет служить для нотификации. Он реализует INotifyPropertyChangedинтерфейс и может быть базовым классом для всех вью моделей.
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T target, T source, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(target, source))
{
return false;
}
target = source;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
return true;
}
}
И еще один абстрактный класс ValidatableViewModelBase, который наследуется от нашего ViewModelBase и реализует интерфейс IDataErrorInfo. От него будут наследоваться все вью модели, на которых необходимо что-либо валидировать:
public abstract class ValidatableViewModelBase : ViewModelBase, IDataErrorInfo
{
private string _error;
public string Error
{
get => _error;
private set => SetProperty(ref _error, value);
}
public string this[string columnName] => Error = Validate(columnName);
protected abstract string Validate(string columnName);
}
И в итоге вью модель целиком будет выглядеть так:
Наследуется от нашего ValidatableViewModelBase и в Validate() методе мы прописываем нашу валидацию, где columnName - имя нашего свойства (Year в нашем примере).
public class MainViewModel : ValidatableViewModelBase
{
private string _year;
public string Year
{
get => _year;
set => SetProperty(ref _year, value);
}
protected override string Validate(string columnName)
{
if (columnName == nameof(Year))
{
if (String.IsNullOrWhiteSpace(Year))
{
return "Year field can not be empty";
}
if (!Int32.TryParse(Year, out var value))
{
return "Year field can not be converted into number";
}
}
return String.Empty;
}
}
Я предлагаю использовать для всех TextBox'ов биндинг на string свойство, потому что считаю, что парсингом и валидацией должна заниматься непостредственно вью модель, но никак не вьюха.
Результат:
Почитать:
- 6,384
Вот что-то такое тебе нужно. Допускается ввод только 0-9 и срабатывание по нажатию Enter. Этот обработчик нужно прикрутить к textBox в событиях, к событию KeyPress в частности.
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
if ((e.KeyChar >= '0' && e.KeyChar <= '9')) return;
if (Char.IsControl(e.KeyChar))
{
if (e.KeyChar == '\r')
{
//был нажат Enter
}
return;
}
else e.Handled = true;
}
- 173

Validation.ErrorTemplate, если надо. – VladD May 20 '17 at 16:10{Binding}и даже не знаете, что это такое? – VladD May 20 '17 at 16:32WPFиWinForms– MihailPw May 20 '17 at 19:44<TextBox Text="{Binding Year, UpdateSourceTrigger=PropertyChanged}"/>+ int-свойство в VM уже достаточно для наблюдаемого эффекта, остальное служит для выдачи понятных пользователю текстовых сообщений (что не так просто!). – VladD May 21 '17 at 18:46