Вопрос

Есть ли лучшая практика или широко распространенный способ структурирования и проверки данных с использованием MVVM в сочетании с RIA-сервисами в Silverlight?

Вот суть моей проблемы. Скажем, у меня есть сотрудник, сотрудничаторВизмModel и какой-то субъект сотрудника. В обычных приложениях RIA я буду выдержать, что субъект сотрудника по мнению, и я получаю проверку «бесплатно», потому что объекты реализуют inotifydataErrorInfo и idataeRrorinfo (правильно?).

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

    private Employee _employee;

    public EmployeeViewModel()
    {
        _employee = new Employee();
    }

    public string Name
    {
        get { return _employee.Name; }
        set
        {
            _employee.Name = value;
            // fire property change, etc.
        }
    }

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

    private Employee _employee;
    public Employee Employee
    {
        get { return _employee; }
    }

    public EmployeeViewModel()
    {
        _employee = new Employee();
    }

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

<StackPanel DataContext="{Binding Employee}">
    <TextBox Text="{Binding Name}" />
</StackPanel>

Используя этот метод, мы получаем «свободную» валидацию, но не совсем чистая реализация MVVM.

Третий вариант будет реализовывать inotifydataerrorInfo и iDataErrinfo себя в VMS, но это похоже на ужасное много сантехнического кода, учитывая, насколько легко было бы для меня использовать вышеуказанное решение и иметь что-то немного меньше «чистота», но черт возьми намного проще в конце дня.

Поэтому я предполагаю, что мой вопрос, какой из этих подходов подходит, в какой ситуации? Есть ли лучший подход, который мне не хватает?

Если это актуально, я смотрю на каркас Caliburn.micro MVVM, но я был бы стремиться увидеть ответы, которые вновь применяются.

Это было полезно?

Решение

Я использую RIA с Caliburn.micro и очень доволен своим решением для проверки на стороне клиента.

Что я сделал, положить ValidationBaseViewModel между Screen (предоставляется Caliburn.micro) и моим фактическим приложением VMS (EmployeeViewModel в твоем случае). ValidationBaseViewModel внедрение INotifyDataErrorInfo Так что этот сантехнический кодекс вы говорите, только один раз. Затем я добавляю / удаляю / уведомляю об ошибках через ValidationBaseViewModel от переопределения (Caliburn.micro) PropertyChangedBase.NotifyOfPropertyChange со следующим кодом:

public override void NotifyOfPropertyChange(string property)
{
    if (_editing == null)
        return;

    if (HasErrors)
        RemoveErrorFromPropertyAndNotifyErrorChanges(property, 100);

    if (_editing.HasValidationErrors)
    {
        foreach (var validationError in
                       _editing.ValidationErrors
                               .Where(error => error.MemberNames.Contains(property)))
        {
            AddErrorToPropertyAndNotifyErrorChanges(property, new ValidationErrorInfo() { ErrorCode = 100, ErrorMessage = validationError.ErrorMessage });
        }
    }

    base.NotifyOfPropertyChange(property);
}

Это на самом деле в другом виртуальной машине (между ValidationBaSeviewModel и OthereeeviewModel) со следующим определением:

public abstract class BaseEditViewModel<TEdit> :
                                ValidationBaseViewModel where TEdit : Entity

куда Entity это слияние System.ServiceModel.DomainServices.Client.Entity и то _editing Участник класса является экземпляром этого типа TEdit который редактируется текущей VM.

В сочетании с Caliburn Conoutines это позволяет мне делать несколько прохладных вещей, как следующее:

[Rescue]
public IEnumerable<IResult> Save()
{
    if (HasErrors)
    {
        yield return new GiveFocusByName(PropertyInError);
        yield break;
    }

    ...
}

Другие советы

Если вы не хотите использовать внешние ресурсы или рамки, то я мог бы иметь ViewModelBase Это реализует INotifyDataErrorInfo.

Этот класс будет иметь ValidateProperty(string propertyName, object value) проверить специфическое свойство и Validate() Метод для подтверждения всего объекта. Внутренне используют Validator класс, чтобы вернуть ValidationResultс.
Если вы используете отражатель, это может быть довольно легко достичь, побуждая процесс проверки в Entity класс сам к ViewModelBase.

Хотя это не «свободно», все еще относительно дешево.

Вот образец реализации IDataErrorInfo. Отказ Хотя не проверено, даст вам идею.

public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
{

  /*
   * InotifyPropertyChanged implementation
   * Consider using Linq expressions instead of string names
   */

  public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
  public IEnumerable GetErrors(string propertyName)
  {
    if (implValidationErrors == null) return null;
    return ImplValidationErros.Where(ve =>
      ve.MemberNames.Any(mn => mn == propertyName));
  }

  public bool HasErrors
  {
    get
    {
      return implValidationErrors == null || ImplValidationErros.Any();
    }
  }

  private List<ValidationResult> implValidationErrors;
  private List<ValidationResult> ImplValidationErros
  {
    get
    {
      return implValidationErrors ?? 
        (implValidationErrors = new List<ValidationResult>());
    }
  }
  private ReadOnlyCollection<ValidationResult> validationErrors;
  [Display(AutoGenerateField = false)]
  protected ICollection<ValidationResult> ValidationErrors
  {
    get
    {
      return validationErrors ?? 
        (validationErrors =
        new ReadOnlyCollection<ValidationResult>(ImplValidationErros));
    }
  }
  protected void ValidateProperty(string propertyName, object value)
  {
    ValidationContext validationContext =
      new ValidationContext(this, null, null);
    validationContext.MemberName = propertyName;
    List<ValidationResult> validationResults =
      new List<ValidationResult>();

    Validator.TryValidateProperty(
      value, 
      validationContext, 
      validationResults);

    if (!validationResults.Any()) return;

    validationResults
      .AddRange(ValidationErrors
      .Where(ve =>
        !ve.MemberNames.All(mn =>
          mn == propertyName)));

    implValidationErrors = validationResults;

    if (ErrorsChanged != null)
      ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
  }
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top