最近一直在学习MVVM,网上有很多介绍和资料,但是都不是非常完善,在学习的过程中花费了很多时间,自己感觉已经告一段落了,写出来总结一下,希望大家批评指正。
MVVM模式主要目的
MVVM模式主要目的是现实界面层(View层)与业务逻辑层(ViewModel 层)和数据层实体层(Model层)的解耦。
要实现View层与其它层的解耦,就要从View层的内容说起。View层的内容主要包括两种:数据和操作。数据映射Model层,操作则在ViewModel 层实现。
各层描述
- View层。主要实现界面的布局和设置数据、事件的绑定来源。View层所有数据和操作都要由ViewModel层提供。
- ViewModel层。负责View层的业务逻辑,同时为View层提供数据和调用的命令。
- Command层。实现View层事件或者操作的方法的构建,由ViewModel层调用。
- Model层。主要实现数据模型的构建,由ViewModel层调用。
各层代码介绍
先上项目结构图
Model层代码介绍
Model层的所有类都要继承INotifyPropertyChanged接口,以实现Model类中所有属性变化后自动通知View层进行调整。为此,我设计了Model的基类继承INotifyPropertyChanged接口,然后其他所有的Model类再继承Model基类。
Model基类
using System.ComponentModel;
namespace Model
{
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/*********************************
* 属性通知事件
* PropertyArgs:变换属性的参数
*********************************/
public void RaisePropertyChangedEvent(string PropertyArgs)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyArgs));
}
}
}
普通Model类
using System.Collections.ObjectModel;
namespace Model
{
public class ProductCatagory : NotifyPropertyChangedBase
{
public ProductCatagory()
{
}
private string _ID,_ProductCatagoryName, _ProductCatagoryType;
private DateTime _CreateTime = DateTime.Now, _UpdateTime = DateTime.Now;
public string ID
{
get
{
return _ID == null ? "" : _ID;
}
set
{
_ID = value;
RaisePropertyChangedEvent("ID");
}
}
public string ProductCatagoryName
{
get
{
return _ProductCatagoryName == null ? "" : _ProductCatagoryName;
}
set
{
_ProductCatagoryName = value;
RaisePropertyChangedEvent("ProductCatagoryName");
}
}
public string ProductCatagoryType
{
get
{
return _ProductCatagoryType == null ? "" : _ProductCatagoryType;
}
set
{
_ProductCatagoryType = value;
RaisePropertyChangedEvent("ProductCatagoryType");
}
}
public DateTime CreateTime
{
get
{
return _CreateTime == null ? DateTime.Now : _CreateTime;
}
set
{
_CreateTime = value;
RaisePropertyChangedEvent("CreateTime");
}
}
public DateTime UpdateTime
{
get
{
return _UpdateTime == null ? DateTime.Now : _UpdateTime;
}
set
{
_UpdateTime = value;
RaisePropertyChangedEvent("UpdateTime");
}
}
}
}
Command层代码介绍
Command层主要实现View层中需要用到的所有操作,Command层的操作由ViewModel层调用后提供给View层。和Model层类似,我也设计Command层基类,其他Command层普通类再继承Command层基类。其实,Command层就是实现设计模式中的Command模式,实现调用和具体操作的解耦。
Command层基类
//ICommand接口的三个成员
//public interface ICommand
//{
// void Execute(object Parameter);
// bool CanExecute(object Parameter);
// event EventHandler CanExecuteChanged;
//}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Windows.Input;
using System.Resources;
using System.Configuration;
using Model;
using System.Data;
using System.Data.Common;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Collections.ObjectModel;
namespace Command
{
public class CommandBase : ICommand
{
//自定义
public static string ConnectionString = "user id=sa;password=a;initial catalog=IME;data source=.\\SQLEXPRESS";
public Action<object> ExecuteCommand = null;
public Func<object, bool> CanExecuteCommand = null;
//ICommand三个成员
public event EventHandler CanExecuteChanged = null;
/// <summary>
/// 重载CanExecute函数
/// </summary>
/// <param name="Parameter"></param>
/// <returns></returns>
public bool CanExecute(object Parameter)
{
if (CanExecuteCommand != null)
{
return CanExecuteCommand(Parameter);
}
else
{
return true;
}
}
/// <summary>
/// 重载Execute函数
/// </summary>
/// <param name="Parameter"></param>
public void Execute(object Parameter)
{
if (ExecuteCommand != null)
{
ExecuteCommand(Parameter);
}
}
}
}
ViewModel层代码介绍
ViewModel层是MVVM模式的核心所在,这一层调用Model层和Command层并进行组装在提供给View层使用。View层需要的数据和操作都要在ViewModel层显式的暴露出来。
/// <summary>
/// 在ViewModel层将需要暴露给View层的对象(事件和数据)都定义成显式的属性
/// View层的事件,由ViewModel层的三个命令属性提供
/// View层的数据,由ViewModel层的Model集合提供
/// </summary>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Resources;
using System.Configuration;
using System.Collections.ObjectModel;
using Model;
using Command;
using System.Data;
using System.Data.Common;
using System.Data.Sql;
using System.Data.SqlClient;
using System.Collections.ObjectModel;
namespace ViewModel
{
public class ProductCatagory : CommandBase
{
//命令定义,View层的三个事件对应ViewModel层的三个命令(由Command层提供)
#region 命令
private Command.CommandBase _loaddata, _updatedata, _deletedata, _insertdata;
public Command.CommandBase InsertData
{
get
{
return _insertdata;
}
set
{
_insertdata = value;
}
}
public Command.CommandBase LoadData
{
get
{
return _loaddata;
}
set
{
_loaddata = value;
}
}
public Command.CommandBase UpdateData
{
get
{
return _updatedata;
}
set
{
_updatedata = value;
}
}
public Command.CommandBase DeleteData
{
get
{
return _deletedata;
}
set
{
_deletedata = value;
}
}
#endregion
//数据定义,View层数据对应ViewModel层的数据类或者数据集合类(由Model层提供)
# region 数据
public Model.ProductCatagory ProductCatagoryModel { get; set; }
public ObservableCollection<Model.ProductCatagory> ProductCatagoryOC { get; set; }
#endregion
public ProductCatagory()
{
LoadData = new Command.CommandBase();
LoadData.ExecuteCommand = LoadDataCommand;
UpdateData = new Command.CommandBase();
UpdateData.ExecuteCommand = UpdateDataCommand;
DeleteData = new Command.CommandBase();
DeleteData.ExecuteCommand = DeleteDataCommand;
ProductCatagoryOC = new System.Collections.ObjectModel.ObservableCollection<Model.ProductCatagory>();
LoadDataCommand("");
}
//View层的加载数据命令
public void LoadDataCommand(object Parameter)
{
ProductCatagoryOC.Clear();
StringBuilder sql = new StringBuilder("select * from T_ProductCatagory where ProductCatagoryName like'%" + Parameter + "%'");
SqlConnection con = new SqlConnection(ConnectionString);
SqlCommand com = new SqlCommand(sql.ToString(), con);
SqlDataAdapter adapter = new SqlDataAdapter(com);
DataTable dt = new DataTable();
try
{
con.Open();
adapter.Fill(dt);
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
ProductCatagoryModel = new Model.ProductCatagory();
ProductCatagoryModel.ID = dr["ID"].ToString();
ProductCatagoryModel.ProductCatagoryName = dr["ProductCatagoryName"].ToString();
ProductCatagoryModel.ProductCatagoryType = dr["ProductCatagoryType"].ToString();
ProductCatagoryModel.CreateTime = string.IsNullOrEmpty(dr["CreateTime"].ToString()) ? DateTime.Now : DateTime.Parse(dr["CreateTime"].ToString());
ProductCatagoryModel.UpdateTime = string.IsNullOrEmpty(dr["UpdateTime"].ToString()) ? DateTime.Now : DateTime.Parse(dr["UpdateTime"].ToString());
ProductCatagoryOC.Add(ProductCatagoryModel);
}
}
}
catch (Exception ee)
{
}
finally
{
com.Dispose();
com = null;
con.Dispose();
con.Close();
con = null;
}
}
//View层的更新数据命令
public void UpdateDataCommand(object Parameter)
{
ProductCatagoryModel = Parameter as Model.ProductCatagory;
//没有ID说明是新添加的数据
if (string.IsNullOrEmpty(ProductCatagoryModel.ID))
{
InsertDataCommand(Parameter);
return;
}
bool returnbool = true;
StringBuilder sql = new StringBuilder("update T_ProductCatagory set ProductCatagoryName='" + ProductCatagoryModel.ProductCatagoryName + "',ProductCatagoryType='" + ProductCatagoryModel.ProductCatagoryType + "' where ID='" + ProductCatagoryModel.ID + "'");
SqlConnection con = new SqlConnection(ConnectionString);
SqlCommand com = new SqlCommand(sql.ToString(), con);
DataTable dt = new DataTable();
try
{
con.Open();
returnbool = com.ExecuteNonQuery() > 0 ? true : false;
}
catch (Exception ee)
{
}
finally
{
com.Dispose();
com = null;
con.Dispose();
con.Close();
con = null;
}
}
//View层的删除数据命令
public void DeleteDataCommand(object Parameter)
{
ProductCatagoryModel = Parameter as Model.ProductCatagory;
if (string.IsNullOrEmpty(ProductCatagoryModel.ID))
{
return;
}
bool returnbool = true;
StringBuilder sql = new StringBuilder("delete from T_ProductCatagory where Id='" + ProductCatagoryModel.ID + "'");
SqlConnection con = new SqlConnection(ConnectionString);
SqlCommand com = new SqlCommand(sql.ToString(), con);
try
{
con.Open();
returnbool = com.ExecuteNonQuery() > 0 ? true : false;
}
catch (Exception ee)
{
}
finally
{
com.Dispose();
com = null;
con.Dispose();
con.Close();
con = null;
}
}
//View层的增加数据命令
public void InsertDataCommand(object Parameter)
{
ProductCatagoryModel = Parameter as Model.ProductCatagory;
if (string.IsNullOrEmpty(ProductCatagoryModel.ID))
{
return;
}
bool returnbool = true;
StringBuilder sql = new StringBuilder("insert into T_ProductCatagory ('" + ProductCatagoryModel.ProductCatagoryName + "','" + ProductCatagoryModel.ProductCatagoryType + "','" + DateTime.Now.ToString() + "','" + DateTime.Now.ToString() + "')");
SqlConnection con = new SqlConnection(ConnectionString);
SqlCommand com = new SqlCommand(sql.ToString(), con);
try
{
con.Open();
returnbool = com.ExecuteNonQuery() > 0 ? true : false;
}
catch (Exception ee)
{
}
finally
{
com.Dispose();
com = null;
con.Dispose();
con.Close();
con = null;
}
}
}
}
为方便大家理解,我把数据库的操作代码也放在了这里,其实是放在Command普通类中调用才好,这也是我没有贴出
Command普通类的原因,我懒
View层代码
View层前台XMAL
<Window x:Class="IMEWpf.CatagoryView.ProductCatagory"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:assembly="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:IMEWpf.CatagoryView"
Title="ProductCatagory" Height="500" Width="500">
<Window.Resources>
<!--自定义ObjectDataProvider数据,引用后台的Enum类型数据-->
<ObjectDataProvider x:Key="KeyProductCatagoryType" MethodName="GetValues" ObjectType="{x:Type assembly:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type Type="local:ProductCatagoryTypeEnum" ></x:Type>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<Canvas>
<DataGrid x:Name="DataGrid1" ItemsSource="{Binding}" AutoGenerateColumns="False" Height="300" Width="450" CanUserAddRows="False" RowEditEnding="DataGrid1_RowEditEnding" LayoutUpdated="DataGrid1_LayoutUpdated">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="选择" Width="50"></DataGridCheckBoxColumn>
<DataGridTextColumn IsReadOnly="True" Header="ID" Width="50" Binding="{Binding Path=ID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
<DataGridTextColumn Header="产品名称" Width="100" Binding="{Binding Path=ProductCatagoryName,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
<DataGridTemplateColumn Header="产品类别">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=ProductCatagoryType}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="taskCombo" ItemsSource="{Binding Source={StaticResource KeyProductCatagoryType},Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="创建时间" Width="100" Binding="{Binding Path=ProductCatagoryCreateTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
<DataGridTextColumn Header="修改时间" Width="100" Binding="{Binding Path=ProductCatagoryUpdateTime, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<Button Name="btnQuery" Command="{Binding LoadData}" Content="查询" Height="23" HorizontalAlignment="Left" Width="75" Margin="163,361,0,0" VerticalAlignment="Top" Canvas.Left="-151" Canvas.Top="-3" />
<Button Name="btnEdit" Command="{Binding UpdateData}" CommandParameter="{Binding ElementName=DataGrid1,Path=SelectedItem}" Canvas.Left="256" Canvas.Top="358" Content="保存" Height="23" Width="75" />
<Button Name="btnDelete" Command="{Binding DeleteData}" Canvas.Left="375" Canvas.Top="358" Content="删除" Height="23" Width="75" />
<Button Name="btnAdd" Canvas.Left="129" Canvas.Top="358" Content="添加" Height="23" Width="75" Click="btnAdd_Click">
</Button>
</Canvas>
</Window>
View层后台代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Shapes;
namespace IMEWpf.CatagoryView
{
public enum ProductCatagoryTypeEnum { 旋翼, 固定翼 };
/// <summary>
/// ProductCatagory.xaml 的交互逻辑
/// </summary>
public partial class ProductCatagory : Window
{
int mutext = 0;//判断当前是增加:0还是修改:1
ViewModel.ProductCatagory pcVM;
public ProductCatagory()
{
InitializeComponent();
pcVM = new ViewModel.ProductCatagory();
this.DataGrid1.DataContext = pcVM.ProductCatagoryOC;
this.btnQuery.DataContext = pcVM;
this.btnEdit.DataContext = pcVM;
this.btnDelete.DataContext = pcVM;
this.btnAdd.DataContext = pcVM;
}
//编辑完以后执行其他时间之前触发此事件
private void DataGrid1_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
}
//设置DataGrid1开关添加状态
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
DataGrid1.CanUserAddRows = true;
}
//隐藏DataGrid1第一列
private void DataGrid1_LayoutUpdated(object sender, EventArgs e)
{
if (DataGrid1.Columns.Count >= 1)
{
this.DataGrid1.Columns[1].Visibility = System.Windows.Visibility.Hidden;
}
}
}
}
欢迎转载,转载请注明出处!