2012-06-09 3 views
0

Я изучаю MVVM прямо сейчас. Поскольку я видел, что многие учебники или проекты используют только View и ViewModel, я немного смущен. Это мой код.Как поместить свойство guard в этот код?

МОДЕЛЬ:

public class StudentModel : PropertyChangedBase 
{ 
    private String _firstName; 
    public String FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      _firstName = value; 
      NotifyOfPropertyChange(() => FirstName); 
     } 
    } 

    private Double _gradePoint; 
    public Double GradePoint 
    { 
     get { return _gradePoint; } 
     set 
     { 
      _gradePoint = value; 
      NotifyOfPropertyChange(() => GradePoint); 
     } 
    } 
} 

ВИД:

<UserControl x:Class="MVVMLearningWithCaliburnMicro.Views.StudentView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:cal="http://www.caliburnproject.org"> 
    <Grid Width="525" Height="300" Background="Lavender"> 
     <DockPanel> 
      <TextBlock HorizontalAlignment="Center" Text="Student Data" 
         DockPanel.Dock="Top" FontSize="20" /> 
      <StackPanel Orientation="Vertical" HorizontalAlignment="Center" 
         VerticalAlignment="Stretch" 
         Margin="0,8" DockPanel.Dock="Top"> 
       <StackPanel Orientation="Horizontal" Margin="0,5"> 
        <TextBlock Text="Name" FontSize="15" Margin="5,0" /> 
        <TextBox Name="txtName" Text="{Binding Path=Student.FirstName}" Width="250" /> 
       </StackPanel> 
       <StackPanel Orientation="Horizontal" Margin="0,5"> 
        <TextBlock Text="Grade" FontSize="15" Margin="5,0" /> 
        <TextBox Name="txtGrade" Text="{Binding Path=Student.GradePoint}" Width="250" /> 
       </StackPanel> 
      </StackPanel> 
      <StackPanel Orientation="Horizontal" Margin="0,5" HorizontalAlignment="Center" 
         VerticalAlignment="Bottom" 
         DockPanel.Dock="Bottom"> 
       <Button Name="btnSave" Width="100" Height="40" 
         cal:Message.Attach="SaveStudent"> 
        <TextBlock Text="Save" FontSize="15" /> 
       </Button> 
      </StackPanel> 
     </DockPanel> 
    </Grid> 
</UserControl> 

ViewModel:

public class StudentViewModel 
{ 
    public StudentModel Student { get; set; } 

    public void SaveStudent() 
    { 
     MessageBox.Show(String.Format("Saved: {0} - ({1})", Student.FirstName, Student.GradePoint)); 
    } 

    public StudentViewModel() 
    { 
     Student = new StudentModel { FirstName = "Tom Johnson", GradePoint = 3.7 }; 
    } 

    private Boolean CanSaveStudent() 
    { 
     return Student.GradePoint >= 0.0 || Student.GradePoint <= 4.0;; 
    } 
} 

Q:
1. Как я могу поместить свою охрану с NotifyOfPropertyChange() в Модели?
2. (Глупый вопрос) Является ли мой шаблон MVVM правильным?

+1

Что свойство охранник? –

+0

Кстати, вы, вероятно, даже не нуждаетесь в модели представления в этом случае. Обычно View должен привязываться к свойствам ViewModel, которые запускают NotifyPropertyChanged и распространяют изменения в модели. Не подразумевая, что вы делаете это неправильно, просто мои небольшие центы. –

+0

Свойство Guard - это свойство, которое используется для охраны события. Это похоже на проверку при запуске события. – asakura89

ответ

2

Один решений наследуют ViewModel от PropertyChangedBase и подписаться на изменения имущественных StudentModel. Затем переведите метод защиты в собственность, например:

public class StudentViewModel: PropertyChangedBase 
{ 
    public StudentModel Student { get; set; } 

    public void SaveStudent() 
    { 
     MessageBox.Show(String.Format("Saved: {0} - ({1})", Student.FirstName, Student.GradePoint)); 
    } 

    public StudentViewModel() 
    { 
     Student = new StudentModel { FirstName = "Tom Johnson", GradePoint = 3.7 }; 
     Student.PropertyChanged += delegate { NotifyOfPropertyChanged(() => CanSaveStudent)}; 
    } 

    public Boolean CanSaveStudent 
    { 
     get 
     { 
      return Student.GradePoint >= 0.0 || Student.GradePoint <= 4.0; 
     } 
    } 
} 

Надеюсь, что это сработает.

+0

Но в этом случае я предлагаю вам объединить viewmodel и модель. –

+0

Тогда мой рисунок будет VVM. Есть ли более чистый способ сделать, если я хочу отдельные VM и M? – asakura89

+0

В MVVM нет ограничений по дизайну на наличие моделей childview в пределах viewmodel. В моем ответе я показал внутренний экземпляр PropertyChangedBase, уведомляющий родительский viewModel. –

1

Уведомлять событие должно присутствовать в view model, потому что он передает изменения из model и подтолкнуть их к UI и наоборот. Это соответствует руководящим принципам MVVM.

В вашем конкретном случае, вы можете или оставить как есть, но удалить ненужные view model или переместить оповещатель в view model

+0

Что в Модели тогда? – asakura89

+0

Модель - это то, что * отражает * вашу базу данных или что-то, что * является * данными само по себе. – Tigran

0

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

Подводя итоги.

ViewModel - должен реализовать интерфейс INotifyPropertyChangeed Модель - должен реализовывать интерфейс INotifyPropertyChangeed

Чтобы включить/отключить команды/кнопки вы должны использовать команду связывания. У меня есть учебник для WPF и Silverlight, с которыми вы можете ссылаться.

http://tsells.wordpress.com/2010/06/23/command-binding-with-wpf-and-silverlight-net-4-0-with-m-v-vm/

Я также положил некоторые учебники на протяжении последних нескольких лет, окружающих эту самую вещь. Проверьте их, если хотите.

http://tsells.wordpress.com/2011/02/08/using-reflection-with-wpf-and-the-inotifypropertychanged-interface/

http://tsells.wordpress.com/2010/06/02/wpf-model-view-viewmodel-m-v-vm-example/

+0

Он использует среду Caliburn.Micro. –

0

Хорошо, у меня есть заключение в моем коде
Here're мои вдохновители

@tsells - спасибо за 3-й линии

@John polvora - - спасибо за указание имущества
ВАЖНО: Это должно быть государственной собственностью

Guard Clause Not Firing
Error on guard clause with Caliburn.Micro


И here're мои коды, которые я думаю, способ более чистых

МОДЕЛЬ:

public class StudentModel 
{ 
    public String FirstName { get; set; } 
    public Double GradePoint { get; set; } 
} 

ВИД:

<UserControl x:Class="MVVMWithCMTwo.Views.StudentView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
      xmlns:cal="http://www.caliburnproject.org"> 
    <Grid Width="525" Height="300" Background="Lavender"> 
     <DockPanel> 
      <TextBlock HorizontalAlignment="Center" Text="Student Data" 
         DockPanel.Dock="Top" FontSize="20" /> 
      <StackPanel Orientation="Vertical" HorizontalAlignment="Center" 
         VerticalAlignment="Stretch" 
         Margin="0,8" DockPanel.Dock="Top"> 
       <StackPanel Orientation="Horizontal" Margin="0,5"> 
        <TextBlock Text="Name" FontSize="15" Margin="5,0" /> 
        <TextBox Name="txtName" Text="{Binding Path=StudentName}" Width="250" /> 
       </StackPanel> 
       <StackPanel Orientation="Horizontal" Margin="0,5"> 
        <TextBlock Text="Grade" FontSize="15" Margin="5,0" /> 
        <TextBox Name="txtGrade" Text="{Binding Path=StudentGrade}" Width="250" /> 
       </StackPanel> 
      </StackPanel> 
      <StackPanel Orientation="Horizontal" Margin="0,5" HorizontalAlignment="Center" 
         VerticalAlignment="Bottom" 
         DockPanel.Dock="Bottom"> 
       <Button Name="btnSave" Width="100" Height="40" 
         cal:Message.Attach="SaveStudent"> 
        <TextBlock Text="Save" FontSize="15" /> 
       </Button> 
      </StackPanel> 
     </DockPanel> 
    </Grid> 
</UserControl> 

ViewModel:

public class StudentViewModel : PropertyChangedBase 
{ 
    public StudentModel Student { get; set; } 

    public String StudentName 
    { 
     get { return Student.FirstName; } 
     set 
     { 
      Student.FirstName = value; 
      NotifyOfPropertyChange(() => Student.FirstName); 
     } 
    } 

    public Double StudentGrade 
    { 
     get { return Student.GradePoint; } 
     set 
     { 
      Student.GradePoint = value; 
      NotifyOfPropertyChange(() => Student.GradePoint); 
      NotifyOfPropertyChange(() => CanSaveStudent); 
     } 
    } 

    public void SaveStudent() 
    { 
     MessageBox.Show(String.Format("Saved: {0} - ({1})", Student.FirstName, Student.GradePoint)); 
    } 

    public StudentViewModel() 
    { 
     Student = new StudentModel { FirstName = "Tom Johnson", GradePoint = 3.7 }; 
    } 

    public Boolean CanSaveStudent 
    { 
     get { return Student.GradePoint >= 0.0 && Student.GradePoint <= 4.0; } 
    } 
} 
+1

Да, вы сделали то, что я рекомендовал (объединили ваш StudentModel внутри StudentViewModel). Вам больше не нужна публичная собственность для StudentModel, она может быть частной. И в представлении вам не нужно объявлять explcit Binding {} ... просто измените имена элементов управления, соответствующие общедоступным свойствам viewmodel и Caliburn.Micro создадут привязки. –

+0

Yup. Я знаю конвенцию. Просто любите старый подход – asakura89