2

有人可以向我解释如何为 MVVM 模式创建 ViewModel。我试图理解这里的教程:http: //msdn.microsoft.com/en-us/magazine/dd419663.aspx,但我无法理解代码中到底发生了什么。

假设我们要创建一个基本应用程序,用于从本地数据库中获取和添加人员,并在视图中显示他们。ViewModel 应该是什么样子以及如何为它创建 RelayCommands。首先,我们为什么要设置两次变量:一次是私下,然后是公开。

编辑:感谢您到目前为止的帮助。我还有一件事我不知道要做 - 如何将 View 绑定到 ViewModel 和反之亦然

这是模型:

public class Student : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private string name;
    private string surname;
    private string age;

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Surname
    {
        get
        {
            return surname;
        }
        set
        {
            surname = value;
            OnPropertyChanged("Surname");
        }
    }

    public string Age
    {
        get
        {
            return age;
        }
        set
        {
            age = value;
            OnPropertyChanged("Age");
        }
    }
}

这是视图模型:

public class MainViewModel : ViewModelBase
{
    ObservableCollection<Student> studentList;
    Student selectedPerson;

    public MainViewModel()
    {
        //populate some sample data
        studentList = new ObservableCollection<Student>()
    {
        new Student(){Name="John", Surname="Smith", Age="28"},
        new Student(){Name="Barbara", Surname="Anderson", Age="23"}
    };
    }

    public ObservableCollection<Student> StudentList
    {
        get { return studentList; }
    }

    public Student SelectedPerson
    {
        get { return selectedPerson; }
        set
        {
            selectedPerson = value;
            RaisePropertyChanged("SelectedPerson");
        }
    }

    private RelayCommand _addStudentCommand;
    public ICommand AddStudentCommand
    {
        get
        {
            return _addStudentCommand
                ?? (_addStudentCommand = new RelayCommand(() =>
                {
                    Student student = new Student();
                    studentList.Add(student);
                }));
        }
    }
}

我找到了一种使用 Csharp 中视图的一些代码将 ViewModel 绑定到 View 的方法,但是如何将 View 绑定到 ViewModel 的问题仍然在我的脑海中。更具体地说,如何使用用户在视图中输入的值创建新学生。

这是视图的 XAML 代码

<Window x:Class="MVVMLight.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" 
    SizeToContent="WidthAndHeight">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="2*"/>
        <RowDefinition Height="2*"/>
        <RowDefinition Height="2*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <TextBlock x:Name="NameTextBlock"
               Text="Name"
               Style="{StaticResource TextBlockTextStyle}"/>
    <TextBlock x:Name="SurnameTextBlock"
               Grid.Row="1"
               Text="Surname"
               Style="{StaticResource TextBlockTextStyle}"/>
    <TextBlock x:Name="AgeTextBlock"
               Grid.Row="2"
               Text="Age"
               Style="{StaticResource TextBlockTextStyle}"/>
    <TextBox x:Name="NameTextBox"
             Grid.Column="1"
             Style="{StaticResource TextBoxTextStyle}"/>
    <TextBox x:Name="SurnameTextBox"
             Grid.Row="1"
             Grid.Column="1"
             Style="{StaticResource TextBoxTextStyle}"/>
    <TextBox x:Name="AgeTextBox"
             Grid.Row="2"
             Grid.Column="1"
             Style="{StaticResource TextBoxTextStyle}"/>
    <ListBox x:Name="StudentListBox"
             Grid.ColumnSpan="2"
             Grid.Row="4"
             Style="{StaticResource ListBoxStyle}"
             ItemsSource="{Binding StudentList}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Name}"
                               Style="{StaticResource TextBlockTextStyle}"/>
                    <TextBlock Text="{Binding Surname}"
                               Grid.Column="1"
                               Style="{StaticResource TextBlockTextStyle}"/>
                    <TextBlock Text="{Binding Age}"
                               Grid.Column="2"
                               Style="{StaticResource TextBlockTextStyle}"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button x:Name="AddButton"
            Grid.Row="7"
            Grid.ColumnSpan="2"
            HorizontalAlignment="Center"
            Content="Add"
            Margin="7,7,7,7"
            Command="{Binding AddStudentCommand}"/>        
</Grid>

这是 View 的 Csharp 代码

 public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
    }
}

我对 View 和 ViewModel 之间的绑定有一些疑问:使用这种类型的绑定有什么优缺点?如果我要使用数据库,最好的绑定方式是什么?

  1. ViewModel 和 Model 应该是这样的吗
  2. 如何创建 RelayCommand 以将学生添加到 ObservableCollection
  3. 为什么我们先私下设置,然后再公开 [已回答]
  4. 如何将视图绑定到 ViewModel 和反之亦然
4

1 回答 1

3

在你的属性设置器中,你应该检查新值是否等于旧值,如果是,你应该返回而不是触发 PropertyChanged 事件。

至于你的问题:

  1. 是的,这看起来不错。
  2. 有几种方法可以设置您的中继命令。我更喜欢

    private RelayCommand<Student> _addStudentCommand;
    public ICommand AddStudentCommand
    {
        get
        {
            return _addStudentCommand
                ?? (_addStudentCommand = new RelayCommand<Student>((student) =>
                    {
                         studentList.Add(student);
                    }));
        }
    }
    

另一种不传入学生对象的方法

private RelayCommand _addStudentCommand;
    public ICommand AddStudentCommand
    {
        get
        {
            return _addStudentCommand
                ?? (_addStudentCommand = new RelayCommand(() =>
                    {
                        Student student = new Student(); 
                        studentList.Add(student);
                    }));
        }
    }
  1. 这就是属性在 .net 中的工作方式,您可以使用自动属性,但由于您需要在 setter 中触发更改通知,因此您必须声明该属性将针对的字段。

此外,由于看起来您正在使用 mvvm light,您应该尝试代码片段。它们使属性非常容易创建。键入 mvvvminpc 然后按两次制表符。然后填写突出显示的部分并点击选项卡,直到完成。

您可以通过几种方式将 View 绑定到 Viewmodel。我知道这是一个反模式,但你可以使用定位器。基本思想是将视图模型设置为视图数据上下文。

public class Locator
{
   public Viewmodel1 Viewmodel1
    {
       return new Viewmodel1();
    }   
}  

然后,您在 app.xaml 中添加此类

<Application.Resources>
   <Locator x:key="VMLocator" />
</Application.Resources>

然后在您的 xaml 视图中

<Page  DataContext="{Binding Source="{StaticResource VMLocator}" Path=ViewModel1}">

</Page>
于 2013-11-14T20:25:19.610 回答