3

Есть TextBox в которые пользотель вводит числа или буквы. Нужно проверить и при вводе букв допустим в "год" выдать ошибку.

MihailPw
  • 6,384
  • 1
    Привяжите ваш textbox к целочисленному свойству и переопределите Validation.ErrorTemplate, если надо. – VladD May 20 '17 at 16:10
  • А как реализовать проверку? – Keti Dzebniauri May 20 '17 at 16:20
  • Проверка сама организуется :) Попробуйте! Увидите красную рамку для неправильно введённого текста. – VladD May 20 '17 at 16:21
  • Где это и как надо прописать? – Keti Dzebniauri May 20 '17 at 16:23
  • А вы привязали textbox к целочисленному свойству? Вы вообще используете DataContext, или программируете обмен данными вручную, как на WinForms? – VladD May 20 '17 at 16:29
  • Нет подскажите пожалуйста как поивязать его и как использовать – Keti Dzebniauri May 20 '17 at 16:30
  • Ох. То есть вы не используете {Binding} и даже не знаете, что это такое? – VladD May 20 '17 at 16:32
  • 1
    Я не смогу написать хороший пример, я с телефона. Но вам бы очень советовал почитать по Binding и MVVM. – VladD May 20 '17 at 16:33
  • А больше вариаетов я просто не успеваю мне скоро сдавать раблту – Keti Dzebniauri May 20 '17 at 16:53
  • может это https://metanit.com/sharp/windowsforms/4.4.php – SergeyE May 20 '17 at 17:53
  • @Eikhner нет. Различайте WPF и WinForms – MihailPw May 20 '17 at 19:44
  • Ну так как можно проверить? – Keti Dzebniauri May 20 '17 at 19:51
  • @KetiDzebniauri Влад вам уже все написал. Сами не попытаетесь понять? – MihailPw May 20 '17 at 19:52
  • @VladD, ваше решение тоже, с удовольствием, бы изучил. По возможности можете набросать? – Андрей NOP May 21 '17 at 10:12
  • @Андрей: Ну, я в полностью согласен с примером AGS17. Единственно, я бы его постарался сделать покороче. <TextBox Text="{Binding Year, UpdateSourceTrigger=PropertyChanged}"/> + int-свойство в VM уже достаточно для наблюдаемого эффекта, остальное служит для выдачи понятных пользователю текстовых сообщений (что не так просто!). – VladD May 21 '17 at 18:46

2 Answers2

4

Лучшее решение, я считаю, это использование прелестей 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 свойство, потому что считаю, что парсингом и валидацией должна заниматься непостредственно вью модель, но никак не вьюха.

Результат:

Результат

Почитать:

MihailPw
  • 6,384
0

Вот что-то такое тебе нужно. Допускается ввод только 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;
        }