【问题标题】:MVVM Creating the ViewModelMVVM 创建 ViewModel
【发布时间】:2013-11-14 17:32:54
【问题描述】:

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

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

编辑:感谢您到目前为止的帮助。我还有一件事我不知道要做 - 如何将 View 绑定到 ViewModel 和 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");
        }
    }
}

这里是 ViewModel:

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);
                }));
        }
    }
}

我找到了一种将 ViewModel 绑定到 View 的方法,使用 Csharp 中的视图的一些代码,但是如何将 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. 如何将 View 绑定到 ViewModel,反之亦然

【问题讨论】:

  • 您的 ViewModel 将有一个 ObservableCollection&lt;Person&gt; 和几个命令,例如 AddPersonCommandRemovePersonCommand。你有什么问题?
  • 您下载了演示项目并浏览了一下代码吗?一旦我这样做了,我很快就清楚了 MVVM 的大部分方面。
  • @HighCore 我的问题是如何定义这些命令
  • @Xaser 我也浏览过。我理解了 INotifyPropertyChange 实现的视图和模型,但我仍然不完全理解 ViewModel
  • 旁注:要非常小心:您几乎每次都将错误的值拼写或传递给 OnPropertyChanged!一般来说,它应该是一个常量字符串,说明属性的名称。

标签: c# wpf mvvm viewmodel


【解决方案1】:

在你的属性设置器中,你应该检查新值是否等于旧值,如果是,你应该返回而不是触发 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,因此您应该尝试使用代码 sn-ps。它们使属性非常容易创建。键入 mvvvminpc 然后按两次制表符。然后填写突出显示的部分并点击选项卡,直到完成。

您可以通过多种方式将视图绑定到视图模型。我知道这是一个反模式,但你可以使用定位器。基本思想是将viewmodel设置为views datacontext。

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>

【讨论】:

  • RelayCommand 类应该如何锁定?编辑:我没有使用 MVVM 轻框架,只是框架使用的方法
  • @GeorgeAnastasov 我不明白 RelayCommand 和 RelayCommand 包含在 mvvm light 工具包中。 RelayCommand 的优点是您不必创建自己的 ICommand 实现。
  • @GeorgeAnastasov 您将在您正在浏览的代码或任何 mvvm 框架中看到 RelayCommand。你不需要自己写。
  • @bland 我添加了 MVVMLight 框架,是的,代码就在那里。注意:我从未尝试使用任何框架
  • @jfin3204 还有一个问题,为什么我不能使用您的代码 sn-p 访问 studentList ObservableCollection,或者我应该说我该如何访问它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2012-09-12
  • 2020-07-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多