سؤال

هل هناك أفضل الممارسات أو طريقة مقبولة على نطاق واسع لتنظيم البيانات والتحقق منها باستخدام MVVM بالتزامن مع خدمات RIA في Silverlight؟

ها هي جوهر مشكلتي. دعنا نقول أن لدي موظف ، موظف exerioreviewmodel وبعض كيان الموظفين. في طلبات 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 و Idataerrorinfo في VMs ، ولكن يبدو أن هذا بمثابة كود فظيع من رمز السباك من أسهل بكثير في نهاية اليوم.

لذلك أعتقد أن سؤالي هو ، أي من هذه الأساليب مناسبة في أي موقف؟ هل هناك نهج أفضل في عداد المفقودين؟

في حال كان من المناسب أن أنظر إلى Caliburn.Micro MVVM Framework ، لكنني سأكون حريصًا على رؤية الإجابات التي تنطبق بشكل عام.

هل كانت مفيدة؟

المحلول

أنا أستخدم 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);
}

هذا بالفعل في VM آخر (بين ValidentBaseViewModel و effecteeViewModel) مع التعريف التالي:

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

أين Entity هو رياس System.ServiceModel.DomainServices.Client.Entity و ال _editing عضو الفصل هو مثيل لهذا النوع TEdit الذي يتم تحريره بواسطة VM الحالي.

بالاشتراك مع Caliburn Coroutines ، يتيح لي هذا القيام ببعض الأشياء الرائعة مثل ما يلي:

[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