学习WPF如果不学MVVM,仿佛缺少了灵魂。那什么是MVVM呢?为什么要学MVVM呢,本以一个简单的增删改查的小例子,简述MVVM的基本知识及如何通过进行MVVM架构的程序开发,仅供学习分享使用,如有不足之处,还请指正。
MVVM是Model-View-ViewModel的简写。它本质上就是MVC (Model-View- Controller)的改进版。即模型-视图-视图模型。分别定义如下:
MVVM示意图如下所示:
项目名称右键-->管理NuGet程序包-->搜索MvvmLight-->安装。如下所示:
弹出接受许可证窗口,点击【接受】如下所示:
MvvmLight安装成功后,自动引用需要的第三方库,并默认生成示例内容,有些不需要的需要删除,如下所示:
主要通过MVVM实现数据的CRUD【增删改查】基础操作,如下所示:
本例主要是对学生信息的增删改查,所以创建Student模型类,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApp3.Models
{
///
/// 学生类
///
public class Student
{
///
/// 唯一标识
///
public int Id { get; set; }
///
/// 学生姓名
///
public string Name { get; set; }
///
/// 年龄
///
public int Age { get; set; }
///
/// 班级
///
public string Classes { get; set; }
}
}
为了简化示例,模拟数据库操作,构建基础数据,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp3.Models;
namespace WpfApp3.DAL
{
public class LocalDb
{
private List students;
public LocalDb() {
init();
}
///
/// 初始化数据
///
private void init() {
students = new List();
for (int i = 0; i < 30; i++)
{
students.Add(new Student()
{
Id=i,
Name=string.Format("学生{0}",i),
Age=new Random(i).Next(0,100),
Classes=i%2==0?"一班":"二班"
});
}
}
///
/// 查询数据
///
///
public List Query()
{
return students;
}
///
/// 按名字查询
///
///
///
public List QueryByName(string name)
{
return students.Where((t) => t.Name.Contains(name)).ToList();//FindAll((t) => t.Name.Contains(name));
}
public Student QueryById(int Id)
{
var student = students.FirstOrDefault((t) => t.Id == Id);
if (student != null)
{
return new Student() {
Id=student.Id,
Name=student.Name,
Age=student.Age,
Classes=student.Classes
};
}
return null;
}
///
/// 新增学生
///
///
public void AddStudent(Student student)
{
if (student != null)
{
students.Add(student);
}
}
///
/// 删除学生
///
///
public void DelStudent(int Id)
{
var student = students.FirstOrDefault((t) => t.Id == Id); //students.Find((t) => t.Id == Id);
if (student != null)
{
students.Remove(student);
}
}
}
}
View层与用户进行交互,用户数据的展示,及事件的响应。在本例中,View层主要有数据查询展示,新增及编辑页面。
在View层,主要是命令的绑定,及数据的绑定。
数据展示窗口,如下所示:
新增及编辑页面,如下所示:
修改学生信息
姓名
年龄
班级
ViewModel层是MVVM的核心所在,起到承上启下的作用。ViewModel需要继承GalaSoft.MvvmLight.ViewModelBase基类。
ViewModel中属性实现数据的绑定,命令实现用户交互的响应。如下所示:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using WpfApp3.DAL;
using WpfApp3.Models;
using WpfApp3.Views;
namespace WpfApp3.ViewModel
{
///
///
///
public class MainViewModel : ViewModelBase
{
#region 属性及构造函数
private LocalDb localDb;
private ObservableCollection gridModelList;
public ObservableCollection GridModelList
{
get { return gridModelList; }
set
{
gridModelList = value;
RaisePropertyChanged();
}
}
///
/// 查询条件
///
private string search;
public string Search
{
get { return search; }
set
{
search = value;
RaisePropertyChanged();
}
}
///
///
///
public MainViewModel()
{
localDb = new LocalDb();
QueryCommand = new RelayCommand(this.Query);
ResetCommand = new RelayCommand(this.Reset);
EditCommand = new RelayCommand(this.Edit);
DeleteCommand = new RelayCommand(this.Delete);
AddCommand = new RelayCommand(this.Add);
}
#endregion
#region command
///
/// 查询命令
///
public RelayCommand QueryCommand { get; set; }
///
/// 重置命令
///
public RelayCommand ResetCommand { get; set; }
///
/// 编辑
///
public RelayCommand EditCommand { get; set; }
///
/// 删除
///
public RelayCommand DeleteCommand { get; set; }
///
/// 新增
///
public RelayCommand AddCommand { get; set; }
#endregion
public void Query()
{
List students;
if (string.IsNullOrEmpty(search))
{
students = localDb.Query();
}
else
{
students = localDb.QueryByName(search);
}
GridModelList = new ObservableCollection();
if (students != null)
{
students.ForEach((t) =>
{
GridModelList.Add(t);
});
}
}
///
/// 重置
///
public void Reset()
{
this.Search = string.Empty;
this.Query();
}
///
/// 编辑
///
///
public void Edit(int Id)
{
var model = localDb.QueryById(Id);
if (model != null)
{
StudentWindow view = new StudentWindow(model);
var r = view.ShowDialog();
if (r.Value)
{
var newModel = GridModelList.FirstOrDefault(t => t.Id == model.Id);
if (newModel != null)
{
newModel.Name = model.Name;
newModel.Age = model.Age;
newModel.Classes = model.Classes;
}
this.Query();
}
}
}
///
/// 删除
///
///
public void Delete(int Id)
{
var model = localDb.QueryById(Id);
if (model != null)
{
var r = MessageBox.Show($"确定要删除吗【{model.Name}】?","提示",MessageBoxButton.YesNo);
if (r == MessageBoxResult.Yes)
{
localDb.DelStudent(Id);
this.Query();
}
}
}
///
/// 新增
///
public void Add()
{
Student model = new Student();
StudentWindow view = new StudentWindow(model);
var r = view.ShowDialog();
if (r.Value)
{
model.Id = GridModelList.Max(t => t.Id) + 1;
localDb.AddStudent(model);
this.Query();
}
}
}
}
当各个层分别创建好后,那如何关联起来呢?答案就是DataContext【数据上下文】。
查询页面上下文,如下所示:
namespace WpfApp3
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainViewModel viewModel = new MainViewModel();
viewModel.Query();
this.DataContext = viewModel;
}
}
}
新增页面上下文,如下所示:
namespace WpfApp3.Views
{
///
/// StudentWindow.xaml 的交互逻辑
///
public partial class StudentWindow : Window
{
public StudentWindow(Student student)
{
InitializeComponent();
this.DataContext = new
{
Model = student
};
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
}
}
MVVM具有低耦合,可重用,可测试,独立开发的优点,核心要素就两个:
本文作为MVVM的简单入门示例,旨在抛砖引玉,一起学习,共同进步。如果对WPF的其他入门知识,不是很了解,可以参考其他博文。
玉楼春·别后不知君远近
欧阳修 〔宋代〕
别后不知君远近,触目凄凉多少闷。渐行渐远渐无书,水阔鱼沉何处问。
夜深风竹敲秋韵,万叶千声皆是恨。故攲单枕梦中寻,梦又不成灯又烬。注:攲(yǐ)