Поддержание WPF MVVM View Model & Model Relationships - PullRequest
5 голосов
/ 04 января 2011

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

Например, если вы изменили свойство Occupation в PersonViewModel, как это изменение сказывается на свойстве Occupation в PersonModel.

Единственный способ, которым я могу видеть это прямо сейчас, - это публичное представление модели в модели представления, но я подумал, что это побеждало цель MVVM - отделение модели от представления.

internal class PersonViewModel : INotifyPropertyChanged
{
    private readonly PersonModel person;

    private OccupationViewModel occupation;

    public PersonViewModel(PersonModel person)
    {
        this.person = person;
    }

    public OccupationViewModel Occupation
    {
        get { return this.occupation; }
        set 
        { 
            if (!this.occupation.Equals(value))
            {
                this.occupation = value;
                this.person.Occupation = this.occupation.Occupation; // Doesn't seem right

                this.OnPropertyChanged(new PropertyChangedEventArgs("Occupation"));
            }
        }
    }
}

internal class OccupationViewModel : INotifyPropertyChanged
{
    public OccupationViewModel(OccupationModel occupation)
    {
        this.Occupation = occupation;
    }

    public OccupationModel Occupation { get; set; } // Is this right?
} 

internal class PersonModel
{
    public OccupationModel Occupation { get; set; }
}

Ответы [ 3 ]

6 голосов
/ 04 января 2011

Ваша модель вида отделяет модель от вида. Похоже, что вы путаете понятия вида и модели представления.

Модель представления является одновременно шлюзом и привратником между ними - она ​​определяет, что делает ее из модели в представление и из представления обратно в модель, и в какой форме.

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

Модель представления может точно знать модель, поэтому представление вообще не должно знать ее.

Я не уверен, что следую вашей озабоченности по поводу публичного показа модели в view-модели. Вы не сделали этого в своем примере кода. Вы выставили объект того же типа , который вы используете в модели, но это все равно, что использовать int для возраста как в модели, так и в модели представления - вы не выставили актуальная модель объекта; у вас все еще есть контроль над тем, когда и когда значение модели представления устанавливается в модели.

5 голосов
/ 07 января 2011

Чтобы показать возможные отношения между Model и ViewModel, я сначала упростил ваш пример, изменив тип Occupation на string.Тогда PersonModel и PersonViewModel могут выглядеть следующим образом:

public class PersonModel : INotifyPropertyChanged
{
  private string occupation;
  public string Occupation
  {
    get
    {
      return this.occupation;
    }
    set
    {
      if (this.occupation != value)
      {
        this.occupation = value;
        this.OnPropertyChanged("Occupation");
      }
    }
  }
}

public class PersonViewModel: INotifyPropertyChanged
{
  private PersonModel model;

  public string Occupation
  {
    get
    {
      return this.model.Occupation;
    }
    set
    {
      this.model.Occupation = value;
    }
  }

  public PersonViewModel(PersonModel model)
  {
    this.model = model;
    this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
  }

  private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    this.OnPropertyChanged(e.PropertyName);
  }
}

Важным отличием вашей версии является то, что PersonModel и PersonViewModel оба реализуют INotifyPropertyChanged.Это важно, потому что в противном случае изменение свойства PersonModel напрямую (т. Е. Без прохождения PersonViewModel) не будет иметь никакого эффекта в представлении.Также обратите внимание, как PropertyChangedEvent из модели передается в представление.

Теперь предположим, что Occupation - это не string, а класс со своими собственными свойствами, например:

public class OccupationModel : INotifyPropertyChanged
{
  private double salary;
  public double Salary
  {
    get
    {
      return this.salary;
    }
    set
    {
      if (this.salary != value)
      {
        this.salary = value;
        this.OnPropertyChanged("Salary");
      }
    }
  }
}

Использование ViewModel между вашим View и Model дает вам некоторую гибкость при представлении ваших данных в View.Вот два варианта, как вы могли бы это сделать:

Опция 1 Предоставить свойства Occupation непосредственно в PersonViewModel.Это простое решение, поскольку вам не нужно реализовывать другую ViewModel.

public class PersonViewModel: INotifyPropertyChanged
{
  private PersonModel model;

  public double OccupationSalary
  {
    get
    {
      return this.model.Occupation.Salary;
    }
    set
    {
      this.model.Occupation.Salary = value;
    }
  }

  public PersonViewModel(PersonModel model)
  {
    this.model = model;
    this.model.Occupation.PropertyChanged += new PropertyChangedEventHandler(occupation_PropertyChanged);
  }

  private void occupation_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    this.OnPropertyChanged("Occupation" + e.PropertyName);
  }
}

Свойство OccupationSalary предоставляет прямой доступ к свойству Salary в Occupation.Обратите внимание, как теперь нужно обрабатывать событие PropertyChanged Occupation, и что нам нужно переименовать свойство в occupation_PropertyChanged.

Option 2 (рекомендуется). Показать свойстваот Occupation до OccupationViewModel.Вы должны сделать это, если вам нужно реализовать какую-либо бизнес-логику, специфичную для Occupation.Учитывая ваш пример, это, вероятно, то, что вы намеревались сделать:

public class PersonViewModel: INotifyPropertyChanged
{
  private PersonModel model;
  private OccupationViewModel occupationViewModel;
  public OccupationViewModel OccupationViewModel
  {
    get
    {
      return this.occupationViewModel;
    }
  }

  public PersonViewModel(PersonModel model)
  {
    this.model = model;
    this.occupationViewModel = new OccupationViewModel(this.model.occupation);
  }
}

public class OccupationViewModel : INotifyPropertyChanged
{
  private OccupationModel model;

  public double Salary
  {
    get
    {
      return this.model.Salary;
    }
    set
    {
      this.model.Salary = value;
    }
  }

  public OccupationViewModel(OccupationModel model)
  {
    this.model = model;
    this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged);
  }

  private void model_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    this.OnPropertyChanged(e.PropertyName);
  }
}

Как видите, OccupationViewModel имеет точно такую ​​же структуру, что и упрощенный PersonViewModel, который я показал в начале.Важное отличие вашей версии OccupationViewModel заключается в том, что она предоставляет свойства из OccupationModel, а не OccupationModel.

0 голосов
/ 04 января 2011

Похоже, вы должны просто предоставить свойство Person в вашей PersonViewModel вместо предоставления свойства Occupation.Свойство Occupation выглядит как ненужный слой.

Свойство person будет выглядеть примерно так, как показано ниже, а на свойство Occupation может ссылаться что-то вроде этого 'viewModel.Person.Occupation'.

        public Person Person
    {
        get
        {
            return this.person;
        }
        set
        {
            if (!this.person.Equals(value))
            {
                this.person = value;
                this.OnPropertyChanged(new PropertyChangedEventArgs("Person"));
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...