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

Когда я впервые отображаю свой экран пользователю, я бы предпочел, чтобы не все сообщения проверки отображались для обязательных полей, например, до того, как пользователь сможет заполнить любое из полей формы. Я установил 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);
    }
}

Ответы [ 3 ]

8 голосов
/ 13 мая 2010

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

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

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

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

2 голосов
/ 16 августа 2012

Просто чтобы указать, как я справился с этим, используя 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() пометьте приватное поле логическим значением как 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);
}

Затем в своем свойстве IDataErrorInfo indexer я делаю следующее (я разделил его, чтобы вручную вызывать 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.

2 голосов
/ 13 мая 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...