MVVM - Валидация - PullRequest
       32

MVVM - Валидация

16 голосов
/ 11 ноября 2010

Мы пытаемся выяснить валидацию в mvvm, делая валидацию в бизнес-логике или модели.Я реализовал валидацию по типу исключения в нашей бизнес-логике - здесь можно найти упрощенную диаграмму: alt text

Если у нас много входных данных, которые не зависят друг от друга, проблем нет, исключение выдается, текстовое поле ловит его, помечая его границы красным цветом для каждого неправильного ввода.Однако, когда у нас есть зависимые ценности, у нас проблемы.например,

  • Value1 и Value2 в модели не должны быть одинаковыми, поэтому у нас есть функция проверки в каждом из тех, кто ищет значение equals, и выдает исключение, если это происходит

  • Теперь, если мы установим Value1 в 0 и Value2 в 1, все будет в порядке

  • Value1 будет установлен в графическом интерфейсе 1 -> thisодин из них помечается красным, поскольку проверка других значений не запускается, поэтому Value2 в графическом интерфейсе не помечается как неисправный

  • Value2 устанавливается в 2 в графическом интерфейсе, теперь мы имеемдостигло допустимого состояния, но проверяется только Value2, поэтому Value1 по-прежнему помечается как неисправный

Существует ли общий шаблон для решения этой проблемы?мы не хотим вводить зависимость в GUI между двумя текстовыми полями, потому что эта логика должна присутствовать только на уровне бизнес-логики.

Вместо реализации проверки по исключению можно также реализовать интерфейс IDataErrorInfo, но проблема все еще существует, нет способа заставить зависимые значения снова проверить их значения, по крайней мере, я не вижу:)

Любая помощь приветствуется

cheers, manni


[очистка, удален ненужный шаг]


15.11.2010 - Part2

хорошо, большое переосмысление здесь, мы идем с бизнес-логическим уровнем.Вот наша текущая запланированная конфигурация: alt text (здесь изображение немного уменьшено, пожалуйста, откройте его в отдельном окне, чтобы показать его в полном размере) все более или менее понятно, кроме как уведомить все модели / модели видаклоны разных редакторов, если изменилась модель данных в соответствии с бизнес-логикой.Один из способов сделать это - отслеживать клонированные модели в бизнес-логике, которая их создает.Когда модель данных изменяется с помощью commit логики бизнес-логики, все другие зарегистрированные клоны модели могут быть уведомлены об изменениях и распространять их дальше.в качестве альтернативы, бизнес-логика могла бы опубликовать событие, на которое подписываются все модели представления, чтобы они тоже получили изменения - кто-нибудь может дать мне подсказку, что лучше?

Еще раз спасибо за помощь, извините, я так противзаблокирован;)

Ответы [ 2 ]

15 голосов
/ 11 ноября 2010

Вы можете использовать интерфейс System.ComponentModel.IDataErrorInfo .Этот очень удобный интерфейс дает вам возможность:

  • выполнять проверку в MVVM-совместимом режиме
  • выполнять пользовательскую проверку для любого конкретного поля (проверка может проверять несколько значений, если вы этого хотитеto)
  • привязать ваш пользовательский интерфейс к ошибкам проверки

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

Вот краткий пример из (WPF)) экран, который собирает некоторые пользовательские данные и выполняет базовую проверку на них:

C # код:

    #region IDataErrorInfo Members

    /// <summary>
    /// Gets an error message indicating what is wrong with this object.
    /// </summary>
    /// <value></value>
    /// <returns>An error message indicating what is wrong with this object. The default is an empty string ("").</returns>
    public override string Error
    {
        get
        {
            return this["UserCode"] + this["UserName"] + this["Password"] + this["ConfirmedPassword"] + this["EmailAddress"];
        }
    }

    /// <summary>
    /// Gets the <see cref="System.String"/> with the specified column name.
    /// </summary>
    /// <value></value>
    public override string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case "UserCode":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 20)
                        return "User Code must be less than or equal to 20 characters";
                    break;

                case "UserName":
                    if (!string.IsNullOrEmpty(UserCode) && UserCode.Length > 60)
                        return "User Name must be less than or equal to 60 characters";
                    break;

                case "Password":
                    if (!string.IsNullOrEmpty(Password) && Password.Length > 60)
                        return "Password must be less than or equal to 60 characters";
                    break;

                case "ConfirmedPassword":
                    if (Password != ConfirmedPassword)
                        return Properties.Resources.ErrorMessage_Password_ConfirmedPasswordDoesntMatch; 
                    break;

                case "EmailAddress":
                    if (!string.IsNullOrEmpty(EmailAddress))
                    {
                        var r = new Regex(_emailRegex);
                        if (!r.IsMatch(EmailAddress))
                            return Properties.Resources.ErrorMessage_Email_InvalidEmailFormat;
                    }
                    break;
            }
            return string.Empty;
        }
    }

    #endregion

, и вот разметка XAML для двух текстовых полей на странице (обратите внимание, в частности, наСвойства ValidatesOnDataErrors и ValidatesOnExceptions в привязке Text:

<TextBox Name="UserCodeTextBox" 
         Text="{Binding UserCode, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,0,150,0"  
         CharacterCasing="Upper"
         />

<TextBox Name="UserNameTextBox" 
         Text="{Binding UserName, 
                Mode=TwoWay, 
                UpdateSourceTrigger=PropertyChanged, 
                ValidatesOnDataErrors=True, 
                ValidatesOnExceptions=True, 
                NotifyOnSourceUpdated=True, 
                NotifyOnTargetUpdated=True}" 
         GotFocus="Input_GotFocus"
         VerticalAlignment="Top"
         Margin="165,30,0,0"  
         />
0 голосов
/ 21 августа 2015

Существует ли общая схема решения этой проблемы?мы не хотим вводить зависимость в GUI между двумя текстовыми полями, потому что эта логика должна присутствовать только на уровне бизнес-логики.

  1. Value1 и Value2 являются взаимозависимыми из-за условия «Значение1 и Значение2 в модели не должны быть одинаковыми».

  2. Это означает, что когда Value2 изменяется, Value1 также изменяется, инаоборот!На самом деле, когда Value2 изменяется, Value1 результат проверки изменяется, но это близко к предыдущему утверждению.

  3. Value1 и Value2 сеттеры должны уведомлять обо всех Value1 и Value2 изменение свойства.

  4. Представление должно перечитать и повторно проверить оба значения и очистить ошибочную метку.

  5. Не уверен, если WPFсделает это, если обнаружит, что событие уведомления было инициировано, но значение фактически не изменилось.

...