Действительно простая проверка данных формы WPF - как?

Я действительно новичок во всей этой вещи WPF, поэтому моя проблема, вероятно, глупо, но, пожалуйста, у меня есть... У меня есть этот действительно простой класс, позвольте назвать его Заказчиком. Это выглядит так:

namespace TestValidation
{
     class Customer
     {
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                if (String.IsNullOrEmpty(value))
                {
                    throw new Exception("Customer name is mandatory.");
                }
            }
        }
    }
}

Теперь я создал базовую форму, в которой пользователь может добавлять клиентов в базу данных. Форма содержит простой TextBox, ограниченный свойством Name клиента и кнопку "Добавить".

Код XAML:

<Window x:Class="TestValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestValidation"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
<TextBox Margin="119,86,107,194" Name="CustomerName"
        Text="{Binding Path=Customer.Name, 
                ValidatesOnExceptions=True, 
                ValidatesOnDataErrors=True,
                UpdateSourceTrigger=PropertyChanged,
                NotifyOnValidationError=True}"
    />
        <Button Content="Add" HorizontalAlignment="Left" Margin="204,176,0,0" VerticalAlignment="Top" Width="74"/>
    </Grid>
</Window> 

Из атрибута свойства Name вы можете понять, что это имя является обязательным для меня, поэтому я хочу, чтобы событие проверки возрастало, если текстовое поле Name осталось без пробела. По правилам проверки WPF - как только пользователь сосредоточится на текстовом поле, и там нет никакой ценности - он должен изменить цвет границы на красный. По какой-то причине это не происходит, и я не знаю, почему. Что не так в моем процессе?

Теперь я прочитал так много хороших статей о Validation в WPF (например, Принятие правил сложных бизнес-данных с WPF, Проверка данных в WPF и Проверка в Windows Presentation Foundation), но ни один из них не помог мне решить мою проблему.

В конце концов, я хочу, чтобы форма была похожа на форму в Brian Noyes, отличная статья по первой ссылке (у меня нет 10 кредитов, поэтому я не могу прикрепить фотографию... извините).

Буду признателен, если кто-нибудь сможет объяснить мне, как это работает.

Важное примечание. Я работаю с .Net framework 4, поэтому мне нужно решение, которое подходит для этой версии.

Ответ 1

Я бы определенно рекомендовал использовать IDataErrorInfo для проверки WPF, поскольку WPF уже понимает, как его использовать, и его легко реализовать.

Для начала добавьте интерфейс в класс, содержащий данные, которые вы хотите проверить. Необходимые методы, вероятно, будут выглядеть примерно так:

public class Customer : IDataErrorInfo
{
    ...

    #region IDataErrorInfo Members

    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            if (columnName == "Name")
            {
                // Validate property and return a string if there is an error
                if (string.IsNullOrEmpty(Name))
                    return "Name is Required";
            }

            // If there no error, null gets returned
            return null;
        }
    }
    #endregion
}

Затем вам нужно установить ValidatesOnDataErrors=True в свою привязку TextBox, чтобы он выполнял проверку при изменении свойства Name:

<TextBox Text="{Binding Path=Customer.Name, ValidatesOnDataErrors=True}" ... />

И, наконец, создайте шаблон проверки в своем XAML, чтобы сообщить WPF, как сделать ошибку проверки. Здесь стиль/шаблон, который я обычно использую:

<!-- ValidatingControl Style -->
<Style TargetType="{x:Type FrameworkElement}" x:Key="ValidatingControl">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding 
                Path=(Validation.Errors)[0].ErrorContent, 
                RelativeSource={x:Static RelativeSource.Self}}" />
        </Trigger>
    </Style.Triggers>
</Style>

Кроме того, убедитесь, что ваш класс Customer реализует INotifyPropertyChanged, чтобы он корректно реагировал на обновления пользовательского интерфейса. Я не вижу этого в вашем коде, но часто люди оставляют это для простоты:)

Ответ 2

Вы не указали правило проверки. Правило проверки будет вызвано до того, как элемент управления будет оставлен, а затем сможет выполнить все, что вы хотите проверить на входы.

Простой пример - и я думаю, что то, что вы хотите сделать, предоставляется здесь.

Ответ 3

Используйте IDataErrorInfo для проверки. ссылка поможет вам.

Ответ 4

Я думаю, проблема может заключаться в том, что ваш класс не реализует INotifyPropertyChanged, поэтому он не является обязательным, как вы ожидаете.

Внедрите интерфейс INotifyPropertyChanged, поднимите событие, когда свойство изменилось и оно должно работать.

См. http://msdn.microsoft.com/en-us/library/ms743695(v=vs.110).aspx для прохода.

Ответ 6

<ControlTemplate x:Key="TextBoxErrorTemplate">
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <Image Height="16" Margin="0,0,5,0" 
                    Source="Assets/warning_48.png"/>
            <AdornedElementPlaceholder x:Name="Holder"/>
        </StackPanel>
        <Label Foreground="Red" Content="{Binding ElementName=Holder, 
               Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
    </StackPanel>
</ControlTemplate> 


<TextBox x:Name="Box" 
         Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
    <TextBox.Text>
        <Binding Path="ValueInBox" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <ValidationExpamples:DoubleRangeRule Min="0.5" Max="10"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>           
</TextBox>



    public class IntRangeRule : ValidationRule
    {
        private int _min;
        private int _max;

        public IntRangeRule()
        {
        }

        public int Min
        {
            get { return _min; }
            set { _min = value; }
        }

        public int Max
        {
            get { return _max; }
            set { _max = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            int l_input = 0;

            try
            {
                if (((string)value).Length > 0)
                {
                    l_input = Int32.Parse((String)value);
                }
            }
            catch (Exception e)
            {
                return new ValidationResult(false, "Illegal characters or " + e.Message);
            }

            if ((l_input < Min) || (l_input > Max))
            {
                return new ValidationResult(false, "Please enter an value in the range: " + Min + " - " + Max + ".");
            }

            return new ValidationResult(true, null);
        }
    }