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

Как я могу заставить WPF НЕ отображать ошибки проверки при первоначальном отображении элемента управления?

Когда я сначала показываю свой экран пользователю, я бы предпочел, чтобы все сообщения проверки не отображались для обязательных полей и, прежде чем пользователь имел возможность заполнить любое из полей формы. Я установил UpdateSourceTrigger в моих привязках к LostFocus, но ошибки все еще отображаются при первом отображении элемента управления. Есть ли способ обойти это?

XAML:

<TextBox Text="{Binding Path=OpeningOdometer, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}" />

ViewModel:

[Required(ErrorMessage = "Please enter the opening odometer.")]
[Range(0, Double.MaxValue, ErrorMessage = "Opening Odometer must be a positive number")]        
public string OpeningOdometer
{
    get { return _openingOdometer; }
    set
    {
        _openingOdometer = value;
        NotifyOfPropertyChange(() => OpeningOdometer);
    }
}

// Implementation of IDataErrorInfo
public string this[string columnName]
{
    get
    {
        // This uses the System.ComponentModel.DataAnnotations placed on
        // the OpeningOdometer property to produce an error string
        // if the value of the property is in violation of any of the 
        // annotated rules.
        return _valHelper.GetErrorsForProperty(columnName, this);
    }
}
4b9b3361

Ответ 1

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

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

По умолчанию сообщение об ошибке обновляется с текущим значением свойства. Всякий раз, когда представление обновляет свойство и запрашивает его новую информацию об ошибке, он получит правильный ответ.

Но у вас также есть довольно мелкомасштабный контроль над тем, что на самом деле в этом словаре. Если вы хотите, чтобы свойство отображалось в пользовательском интерфейсе как действительное, просто очистите его сообщение об ошибке в словаре (и поднимите PropertyChanged, чтобы пользовательский интерфейс знал, чтобы получить новое сообщение об ошибке). Или вы можете установить поля поддержки свойств вместо самих свойств, минуя проверку, когда вы создаете объект модели представления.

Ответ 2

Вы можете получить более качественные ответы, если попытаетесь опубликовать фрагмент вашего соответствующего кода /XAML. Это облегчило бы воспроизведение и устранение значительной части догадок.

Попробуйте установить ValidatesOnTargetUpdated="False" в правилах проверки и посмотрите, помогает ли это.

Ответ 3

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

Я поместил вызов нового метода под названием OnDataUpdated() в каждый набор моего свойства, связанного с представлением, например:

    private string username;
    public string Username
    {
        get { return username; }
        set
        {
            username = value;
            OnDataUpdated();
        }
    }

    private string password;
    public string Password
    {
        get { return password; }
        set
        {
            password = value;
            OnDataUpdated();
        }
    }

Затем внутри OnDataUpdated() отметьте приватное поле boolean как true, указывающее, что данные были изменены в первый раз (FormType было необходимо только для моего бизнес-кейса):

private void OnDataUpdated()
{
   dataChanged = true;
   // .. Any other universal RaisePropertyChanged() events you may want to call to get your UI into sync. Eg. RaisePropertyChanged(() => CanConfirm);
}

Затем в свойстве indexer IDataErrorInfo я делаю следующее (я разделил его так, чтобы "ValidForm()" можно вызвать вручную, чтобы выполнить проверку формы тоже.

public string this[string columnName]
        {
            get
            {
                string result = null;
                if (columnName == "Username")
                {
                    // If other payment amounts have fully paid for balance, and cash amount has been entered, deny
                    if (!ValidForm(FormType.Step1, columnName))
                        result = "Please enter the username field.";
                }
                else if (columnName == "Password")
                {
                    if (!ValidForm(FormType.Step1, columnName))
                        result = "Please enter the password field.";
                }
                return result;
            }
        }

        /// <summary>
        /// Test if valid form.
        /// </summary>
        /// <param name="formType">Specify which form we should validate.</param>
        /// <param name="columnName">If ommitted, entire form will be validated.</param>
        /// <returns></returns>
        private bool ValidForm(FormType formType, string columnName = null)
        {
            // This field is used to denote when data has changed on the form.
            // If data has changed, we know we can activate any form validation.
            // We do not activate the form validation until after a user has typed
            // something in at least.
            if (!dataChanged) return true;

            var errors = false;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Username") && string.IsNullOrEmpty(Username)))
                errors = true;
            if (formType == FormType.Step1 && ((string.IsNullOrEmpty(columnName) || columnName == "Password") && string.IsNullOrEmpty(Password)))
                errors = true;
            return !errors;
        }

Прекрасно работает. Теперь у меня только стили проверки, появляющиеся после того, как пользователь редактирует форму.

Если вы хотите получить дополнительную глазурь на торте, вы можете прокомментировать мой RaisePropertyChanged(() => CanConfirm); в методе OnDataUpdated() и связать это с вашей кнопкой подтверждения IsEnabled={Binding CanConfirm} с соответствующим свойством:

/// <summary>
/// Can the user confirm step 1?
/// </summary>
public bool CanConfirm
{
    get { return ValidForm(FormType.Step1); }
}

и ваша кнопка будет включена, только если ваша форма также действительна.:)

Наслаждайтесь! и удачи с бегемотом, который является WPF.