WPF-MVVM

本文详细介绍了MVVM模式的目的、各层描述及代码实现,包括Model层、Command层和ViewModel层。重点阐述了如何通过MVVM模式实现界面层与业务逻辑层的解耦,提供了具体的代码实例,并附上了数据库操作代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近一直在学习MVVM,网上有很多介绍和资料,但是都不是非常完善,在学习的过程中花费了很多时间,自己感觉已经告一段落了,写出来总结一下,希望大家批评指正。

MVVM模式主要目的

MVVM模式主要目的是现实界面层(View层)与业务逻辑层(ViewModel 层)和数据层实体层(Model层)的解耦。

要实现View层与其它层的解耦,就要从View层的内容说起。View层的内容主要包括两种:数据和操作。数据映射Model层,操作则在ViewModel 层实现。

各层描述

  1. View层。主要实现界面的布局和设置数据、事件的绑定来源。View层所有数据和操作都要由ViewModel层提供。
  2. ViewModel层。负责View层的业务逻辑,同时为View层提供数据和调用的命令。
  3. Command层。实现View层事件或者操作的方法的构建,由ViewModel层调用
  4. 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类

在普通Model类中,所有属性都要在get中调用 RaisePropertyChangedEvent方法,以实现修改属性值时通知View层自动更改。
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层基类

Command基类主要实现继承ICommand接口,这个接口大家可以找资料学习一下,此处不再赘述。
//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;
            }
        }

    }
}

欢迎转载,转载请注明出处!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值