WPF MVVM 入門示例講解
阿新 • • 發佈:2020-09-10
M-V-VM是Model-View-ViewModel的簡寫,Model,ViewModel是個類檔案(.cs檔案),View是前臺檔案(,xaml檔案)。假設我們的工程只有一個前臺檔案和一個後臺檔案,當設計要求越來越多的時候,前後臺文件可能會高達上千行,甚至上萬行,此時要想找到對應的程式碼,滑鼠滾輪會滑的頭大。學習MVVM便於工程除錯,修改,移植。用MVVM如果只是修改或者更好顯示介面,後臺檔案只需稍微的改動甚至不用改動。下面這個例子是V-VM模式就是view和viewmodel,先以簡單的入門,工程集如下:
<Window x:Class="Students.View" xmlnsView.xaml="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Students" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid x:Name ="StudetGrid" Grid.Row ="0"> <Grid.DataContext> <!--宣告建立一個ViewModel的例項,這個聲明確定了ViewModel.cs是VM,這個宣告建立了View.xaml與ViemModel之間的橋樑,這個myGrid所有繫結的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員--> <local:StudetViewModel/> </Grid.DataContext> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="姓名:" Grid.Column="0" HorizontalAlignment="Right"/> <TextBlock Text="{Binding Name}" Grid.Column="1"/> <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right" /> <TextBlock Text="{Binding Age}" Grid.Column="3" /> <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" /> <TextBlock Text="{Binding Sex}" Grid.Column="5"/> <Button Content="更新" Grid.Column="6" Click="BtnClick" /> </Grid> </Grid> </Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Students { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class View : Window { public static StudetViewModel viewModel;//宣告一個類,但是沒有例項化,把這個viewModel設為static方便其他頁面檔案互相訪問繫結的屬性 public View() { InitializeComponent(); viewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中例項化viewModel,這個viewModel就是View.xaml中宣告的那個ViewModel例項,就是那個橋樑。 } private void BtnClick(object sender, RoutedEventArgs e) { viewModel.Name = "小明"; viewModel.Age = "15"; viewModel.Sex = "男"; } } }View.xaml.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace Students { public class StudetViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private string name; public String Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } private string age; public String Age { get { return age; } set { age = value; OnPropertyChanged("Age"); } } private string sex; public String Sex { get { return sex; } set { sex = value; OnPropertyChanged("Sex"); } } } }StudetViewModel.cs
View.xaml是View,那如何確定StudetViewModel.cs就是VM呢?在View.xaml檔案中有如下宣告
在前臺檔案中宣告資料上下文指定類,指定的那個類就是ViewModel。先看一下執行效果吧
這個工程檔案裡的StudetViewModel.cs其實就是Model和ViewModel合在一起了
增加完Model類後的程式集如下:
如何確定PeronModel就Model呢?因為它在ViewModel中有例項化
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace Students { public class StudetViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private PersonModel _studentModel = new PersonModel();//例項化Model中的類 public PersonModel StudentModel { get { return _studentModel; } set { _studentModel = value; OnPropertyChanged("StudentModel"); } } } }StudetViewModel
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace Students { public class PersonModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private string name; public String Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } } private string age; public String Age { get { return age; } set { age = value; OnPropertyChanged("Age"); } } private string sex; public String Sex { get { return sex; } set { sex = value; OnPropertyChanged("Sex"); } } } }Students
<Window x:Class="Students.View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Students" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid x:Name ="StudetGrid" Grid.Row ="0"> <Grid.DataContext> <!--宣告建立一個ViewModel的例項,這個聲明確定了ViewModel.cs是VM,這個宣告建立了View.xaml與ViemModel之間的橋樑,這個myGrid所有繫結的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員--> <local:StudetViewModel/> </Grid.DataContext> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="姓名:" Grid.Column="0" HorizontalAlignment="Right"/> <TextBlock Text="{Binding StudentModel.Name}" Grid.Column="1"/> <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right" /> <TextBlock Text="{Binding StudentModel.Age}" Grid.Column="3" /> <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" /> <TextBlock Text="{Binding StudentModel.Sex}" Grid.Column="5"/> <Button Content="更新" Grid.Column="6" Click="BtnClick" /> </Grid> </Grid> </Window>View
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Students { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class View : Window { public static StudetViewModel viewModel;//宣告一個類,但是沒有例項化,把這個viewModel設為static方便其他頁面檔案互相訪問繫結的屬性 public View() { InitializeComponent(); viewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中例項化viewModel,這個viewModel就是View.xaml中宣告的那個ViewModel例項,就是那個橋樑。 } private void BtnClick(object sender, RoutedEventArgs e) { viewModel.StudentModel.Name = "小明"; viewModel.StudentModel.Age = "15"; viewModel.StudentModel.Sex = "男"; } } }View.xaml.cs
View中例項化過ViewModel,兒ViewModel中例項化過Model,所以說ViewModel建立起了View與Model之間溝通的橋樑。一個ViewModel類中可以有多個不同的Model類的例項,比如我們還可以建立一個成績類(Model),然後在ViewModel中去例項化,最後在View介面中去繫結各科成績,這個好理解。
View中也可以例項化多個ViewModel
程式集如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace Students { public class TeacherViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private PersonModel _teacherModel = new PersonModel();//例項化Model中的類 public PersonModel TeacherModel { get { return _teacherModel; } set { _teacherModel = value; OnPropertyChanged("TeacherModel"); } } } }TeacherViewModel
<Window x:Class="Students.View" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Students" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="30"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid x:Name ="StudetGrid" Grid.Row ="0"> <Grid.DataContext> <!--宣告建立一個ViewModel的例項,這個聲明確定了ViewModel.cs是VM,這個宣告建立了View.xaml與ViemModel之間的橋樑,這個myGrid所有繫結的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員--> <local:StudetViewModel/> </Grid.DataContext> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="學生姓名:" Grid.Column="0" HorizontalAlignment="Right"/> <TextBlock Text="{Binding StudentModel.Name}" Grid.Column="1"/> <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right" /> <TextBlock Text="{Binding StudentModel.Age}" Grid.Column="3" /> <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" /> <TextBlock Text="{Binding StudentModel.Sex}" Grid.Column="5"/> <Button Content="更新" Grid.Column="6" Click="BtnClick" /> </Grid> <Grid x:Name ="TeacherGrid" Grid.Row ="1"> <Grid.DataContext> <!--宣告建立一個ViewModel的例項,這個聲明確定了ViewModel.cs是VM,這個宣告建立了View.xaml與ViemModel之間的橋樑,這個myGrid所有繫結的屬性(Name,Age,Sex)都值的是ViewModel.cs類中的成員--> <local:TeacherViewModel/> </Grid.DataContext> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="老師姓名:" Grid.Column="0" HorizontalAlignment="Right"/> <TextBlock Text="{Binding TeacherModel.Name}" Grid.Column="1"/> <TextBlock Text="年齡:" Grid.Column="2" HorizontalAlignment="Right" /> <TextBlock Text="{Binding TeacherModel.Age}" Grid.Column="3" /> <TextBlock Text="性別:" Grid.Column="4" HorizontalAlignment="Right" /> <TextBlock Text="{Binding TeacherModel.Sex}" Grid.Column="5"/> <Button Content="更新" Grid.Column="6" Click="BtnClickTeacher" /> </Grid> </Grid> </Window>View.xaml
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace Students { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class View : Window { public static StudetViewModel studentViewModel;//宣告一個類,但是沒有例項化,把這個viewModel設為static方便其他頁面檔案互相訪問繫結的屬性 public static TeacherViewModel teacherViewModel; public View() { InitializeComponent(); studentViewModel = StudetGrid.DataContext as StudetViewModel;//在構造方法中例項化viewModel,這個viewModel就是View.xaml中宣告的那個ViewModel例項,就是那個橋樑。 teacherViewModel = TeacherGrid.DataContext as TeacherViewModel; } private void BtnClick(object sender, RoutedEventArgs e) { studentViewModel.StudentModel.Name = "小明"; studentViewModel.StudentModel.Age = "15"; studentViewModel.StudentModel.Sex = "男"; } private void BtnClickTeacher(object sender, RoutedEventArgs e) { teacherViewModel.TeacherModel.Name = "王老師"; teacherViewModel.TeacherModel.Age = "30"; teacherViewModel.TeacherModel.Sex = "女"; } } }View.xaml.cs
效果如下: