MVVM 创建视图模型 [英] MVVM Creating the ViewModel

查看:52
本文介绍了MVVM 创建视图模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can somebody explain to me how exactly to create a ViewModel for the MVVM Pattern. I tried to understand the the tutorial here: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx , but I was unable to understand what exactly is happening in the code.

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

Let's say we want to create a basic application about getting and adding people from and to a local database and displaying them in the View. How should the ViewModel look like and how to create the RelayCommands for it. First why do we set the variables twice: once privately and then again publicaly.

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

Thanks for the help so far. I have one more thing that I don't know to do - how to bind the View to the ViewModel and Vice Versa

这是模型:

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 的问题.更具体地说明如何使用用户在视图中输入的值创建新学生.

I have found a way to bind the ViewModel to the View using some code for the view in Csharp but the question how to bind the View to the ViewModel is still on my mind. To be more specific how to create a new student using the values a user has entered in the View.

这是视图的 XAML 代码

Here is the View's XAML code

<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>

这是视图的 Csharp 代码

And here is the View's Csharp code

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

我有一些关于视图和视图模型之间的绑定的问题:使用这种类型的绑定有什么优点和缺点?如果我要使用数据库,最好的绑定方式是什么?

I have some questions concerning the Binding between the View and The ViewModel: What are the pros and cons of using this type of binding? What is the best way of binding if I am going to use a database?

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

推荐答案

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

in your property setters you should check to see if the new value is equal to the old value, if it is you should return and not fire the PropertyChanged event.

至于您的问题:

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

  1. Yes this looks fine.
  2. There are a couple of ways to setup your relay commands. I prefer

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

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

another way without passing in a student object

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 然后按两次 Tab.然后填写突出显示的部分并点击选项卡直到完成.

Also since it looks like you are using mvvm light you should try the code snippets. They make properties very easy to create. type mvvvminpc then hit tab twice. then fill in the highlighted part and hit tab till you are finished.

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

You can bind the View To the Viewmodel a couple of ways. I know that it is an Antipattern but you could use a locator. The basic idea is to set the viewmodel as the views datacontext.

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

然后在 app.xaml 中添加这个类

You then in you app.xaml you add this class

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

然后在您的 xaml 视图中

Then in your view in the xaml

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

</Page>

这篇关于MVVM 创建视图模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆