Loading

wpf-mvvm开发学习1

最近在做wpf的程序 写到中期越来越恶心 所以尝试重构为MVVM模式

MVVM相关知识

0x01 什么是MVVM

1.Model

Model就是一个class,是对现实中事物的抽象,开发过程中涉及到的事物都可以抽象为Model,例如客户,客户的姓名、编号、电话、住址等属性也对应了class中的Property,客户的下订单、付款等行为对应了class中的方法。

2. View

View很好理解,就是界面。

3. ViewModel

上面说过Model抽象,那么ViewModel就是对View的抽象。显示的数据对应着ViewMode中的Property,执行的命令对应着ViewModel中的Command。

0x02 WPF中MVVM的解耦方式

在WPF的MVVM模式中,View和ViewModel之间数据和命令的关联都是通过绑定实现的,绑定后View和ViewModel并不产生直接的依赖。具体就是View中出现数据变化时会尝试修改绑定的目标。同样View执行命令时也会去寻找绑定的Command并执行。反过来,ViewModel在Property发生改变时会发个通知说“名字叫XXX的Property改变了,你们这些View中谁绑定了XXX也要跟着变啊!”,至于有没有View收到是不是做出变化也不关心。ViewModel中的Command脱离View就更简单了,因为Command在执行操作过程中操作数据时,根本不需要操作View中的数据,只需要操作ViewModel中的Property就可以了,Property的变化通过绑定就可以反映到View上。这样在测试Command时也不需要View的参与。这也是我在接触WPF初期时根本理解不了的所谓数据驱动。

这样一来ViewMode可以在完全没有View的情况下测试,View也可以在完全没有ViewModel的情况下测试(当然只是测试界面布局和动画等业务无关的内容)。

0x3 MVVM框架需要解决的问题

从图中可以看出如果要实现一套MVVM框架,需要解决的最基本的问题就是数据绑定和命令绑定。此外由于UI中会产生大量的事件,因此还需要将事件绑定到MVVM中的命令上。

实战开始

安装

Microsoft.Toolkit.Mvvm

Microsoft.Xaml.Behaviors.Wpf

PropertyChanged.Fody

image-20220524142927427

构建如图项目结构

一个简单demo

ProcessWindowModel.cs Model层

应该声明所需要的类 数据结构)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Toolkit.Mvvm.ComponentModel;
namespace lltool_MVVM.Model {
    internal class ProcessWindowModel {
    }
    public class myProcess : ObservableObject {

        private int _pid;
        private string _pidName;
        private bool _isChecked;
        private int _processSize;
        public int pid
        {
            get { return _pid; }
            set { _pid = value; }
        }
        public string pidName
        {
            get { return _pidName; }
            set { _pidName = value; }
        }
        public bool isChecked
        {
            get { return _isChecked; }
            set { _isChecked = value; }
        }
        public int processSize
        {
            get { return _processSize; }
            set { _processSize = value; }
        }
        
    }
}

ViewModel层

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using lltool_MVVM.Model;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.DependencyInjection;
using Microsoft.Toolkit.Mvvm.Input;
using Microsoft.Toolkit.Mvvm.Messaging;
using Microsoft.Toolkit.Mvvm.Messaging.Messages;
namespace lltool_MVVM.ViewModel {
    public class myProcessViewModel : ObservableObject {
        public myProcessViewModel() {
            //将命令接口与真正的函数绑定
            UpdatePidNameCommand = new RelayCommand(UpdatePidNameExecute);
        }
        private string _pidName;
        //提供的SetProperty<T>(ref T, T, string)方法检查属性的当前值,如果不同则更新它,然后还会自动引发相关事件。
        //属性名称是通过使用[CallerMemberName]属性自动捕获的,因此无需手动指定要更新的属性。
        //暴露出pidName 便于外部进行绑定
        public string pidName
        {
            get { return _pidName; }
            set
            {
                SetProperty(ref _pidName , value);
            }
        }
        void UpdatePidNameExecute() {
            this.pidName = "new name";
            MessageBox.Show(this.pidName);
        }
        //一个接口 用于外部的button绑定
        public ICommand UpdatePidNameCommand { get; }
    }

}

View层

<metro:MetroWindow
    x:Class="lltool_MVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Aduskin="clr-namespace:AduSkin;assembly=AduSkin"
    xmlns:ViewModel="using:lltool_MVVM.ViewModel"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:lltool_MVVM"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:metro="clr-namespace:AduSkin.Controls.Metro;assembly=AduSkin"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <TextBlock Margin="20" Text="{Binding pidName}" />
        <Button Width="100" Height="100" Command="{Binding UpdatePidNameCommand}" Content="点我" />
    </Grid>

</metro:MetroWindow>

MainWindow.xaml.cs

using AduSkin.Controls.Metro;
using lltool_MVVM.ViewModel;
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 lltool_MVVM {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow {
        public MainWindow() {
            InitializeComponent();
            //绑定数据上下文
            DataContext = new myProcessViewModel
            {
                pidName = "2333"
            };
        }
    }
}

结果

image-20220525123732158

image-20220525123738535

posted @ 2022-05-25 12:49  FW_ltlly  阅读(133)  评论(0编辑  收藏  举报