Подтвердить что ты не робот

Проверка WPF TextBox

У меня есть проверка, привязанная к модели, привязанной к контейнеру TextBox. Когда окно открыто, ошибки проверки появляются, когда модель пуста, я не хочу видеть ошибки проверки до тех пор, пока не будет отправлено окно или текст в TextBox не изменился или потерял фокус.

Вот TextBox:

<TextBox Text="{Binding 
                   Path=Firstname, 
                   UpdateSourceTrigger=PropertyChanged, 
                   ValidatesOnDataErrors=True}"
         Width="124"
         Height="24"/>

Как это можно достичь?

4b9b3361

Ответ 1

Это действительно зависит от вашей реализации IDataErrorInfo. Если вы основываете его на словарях сообщений об ошибках, которые вы можете контролировать при запуске проверки, который добавляется в этот список. Вы, как правило, хотели бы сделать это со своими настройщиками свойств (например, когда вы вызываете PropertyChange), здесь вызов CheckValidationState:

    public string this[string columnName]
    {
        get
        {
            return ValidateProperty(columnName);
        }
    }

    public Dictionary<string, string> Errors { get; private set; }

    protected void SetError(string propertyName, string errorMessage)
    {
        Debug.Assert(!String.IsNullOrEmpty(propertyName), "propertyName is null or empty.");
        if (String.IsNullOrEmpty(propertyName))
            return;

        if (!String.IsNullOrEmpty(errorMessage))
        {
            if (Errors.ContainsKey(propertyName))
                Errors[propertyName] = errorMessage;
            else
                Errors.Add(propertyName, errorMessage);
        }
        else if (Errors.ContainsKey(propertyName))
            Errors.Remove(propertyName);

        NotifyPropertyChanged("Errors");
        NotifyPropertyChanged("Error");
        NotifyPropertyChanged("Item[]");
    }

    protected virtual string ValidateProperty(string propertyName)
    {
        return Errors.ContainsKey(propertyName) ? Errors[propertyName] : null;
    }

    protected virtual bool CheckValidationState<T>(string propertyName, T proposedValue)
    {
        // your validation logic here
    }

Затем вы можете также включить метод, который проверяет все ваши свойства (например, во время сохранения):

    protected bool Validate()
    {
        if (Errors.Count > 0)
            return false;

        bool result = true;
        foreach (PropertyInfo propertyInfo in GetType().GetProperties())
        {
            if (!CheckValidationState(propertyInfo.Name, propertyInfo.GetValue(this, null)))
                result = false;
            NotifyPropertyChanged(propertyInfo.Name);
        }
        return result;
    }

UPDATE:

Я бы рекомендовал поместить вышеуказанный код в базовый класс ViewModel, чтобы вы могли его повторно использовать. Затем вы можете создать производный класс следующим образом:

public class SampleViewModel : ViewModelBase
{
    private string _firstName;

    public SampleViewModel()
    {
        Save = new DelegateCommand<object>(SaveExecuted);
    }

    public DelegateCommand<object> Save { get; private set; }

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName == value)
                return;

            CheckValidationState("FirstName", value);

            _firstName = value;
            NotifyPropertyChanged("FirstName");
        }
    }

    public void SaveExecuted(object obj)
    {
        bool isValid = Validate();
        MessageBox.Show(isValid ? "Saved" : "Validation Error. Save canceled"); // TODO: do something appropriate to your app here
    }

    protected override bool CheckValidationState<T>(string propertyName, T proposedValue)
    {
        // your validation logic here
        if (propertyName == "FirstName")
        {
            if (String.IsNullOrEmpty(proposedValue as String))
            {
                SetError(propertyName, "First Name is required.");
                return false;
            }
            else if (proposedValue.Equals("John"))
            {
                SetError(propertyName, "\"John\" is not an allowed name.");
                return false;
            }
            else
            {
                SetError(propertyName, String.Empty); // clear the error
                return true;
            }
        }
        return true;
    }
}

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

Ответ 2

Если вы реализуете IDataErrorInfo, я достиг этого, проверив нулевые значения в реализации логики проверки. При создании нового окна проверка нуля приведет к блокировке вашей логики проверки. Например:

public partial class Product : IDataErrorInfo
{
    #region IDataErrorInfo Members

    public string Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "ProductName")
            {
                // Only apply validation if there is actually a value
                if (this.ProductName != null)
                {
                    if (this.ProductName.Length <= 0 || this.ProductName.Length > 25)
                        return "Product Name must be between 1 and 25 characters";
                }
            }

            return null;
        }
    }

    #endregion
}

Кроме того, если вы хотите запустить проверку в TextBox.LostFocus, измените привязку к LostFocus, например:

<TextBox Text="{Binding              
               Path=Firstname,              
               UpdateSourceTrigger=LostFocus,              
               ValidatesOnDataErrors=True}"             
     Width="124"             
     Height="24"/>

Ответ 3

в вашем файле app.xaml, вам нужно использовать собственный стиль текстового поля для проверки текстового поля без какого-либо стороннего компонента.

enter image description here

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type TextBox}">
            <Grid Name="test">
                <Border Background="{StaticResource TextBackColor}"
                        BorderBrush="#FF888888"
                        x:Name="Bd"
                        CornerRadius="1"
                        BorderThickness="1">
                    <ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
                </Border>
                <Image  Name="ErrorImage"
                        Width="15"
                        Height="15"
                        Margin="0,0,4,0"
                        Source="Images/validate.png"
                        HorizontalAlignment="Right">
                </Image>
            </Grid>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Ответ 4

Что я делаю, я не знаю, правильно ли это (я был бы рад узнать, теперь это шанс), но в инициализаторе объекта или модели я запускаю все валидаторы.