WPF个人文档(七)—— MVVM初见杀
- # MVVM
- View # ?
- ViewModel # ?
- Model # ?
复制代码 温馨提示:请不要企图一次就看懂MVVM架构,也不要妄图一次就明白MVVM,更不要妄想一次就可以上手开写
MVVM架构初期学习,需要反复看,反复学习,反复受折磨,反复骂街,然后接着去学......
别人学习一门架构,需要花数个月,甚至一两年,才能做到完全熟悉里面的每一个东西
所以你就不要想着,一两周甚至几天时间就可以学会并且熟练使用一门架构了
因此,这篇随笔,仅做对MVVM架构的初步了解,而不是去教会你怎么熟练使用
关于标题,初见杀,你以为杀的是谁,是我啊,也是你,
随笔的另一个目的,后面要是忘记了,我们也可以回来回顾回顾,和弄和弄
如果你是第一次接触前端架构,或者你以前没有搞过Web前端什么的,那么
恭喜你,一起一脸蒙圈的看着这MVVM架构吧
前期学习MVVM架构,大脑里面无时无刻浮现出宇宙三大终究问题:我是谁,我在哪,我从哪里来
因为MVVM其实是一门非常复杂的技术架构,涉及的知识点很多很多,但凡你对其中一项核心技术不甚了解
就会像过年的时候被亲戚灌酒喝断片一样——不对,刚刚发生什么了,我没走神吧,怎么一瞬间什么都不明白了
学习MVVM架构,最好去找一个小的教学Demo或者视频,如果你对其中的许多概念感到非常陌生
请去学习前置内容,我就不推荐你继续深入学习MVVM了,
毕竟,第一关那多没意思解锁,就单挑BOSS,你也想给BOSS修脚吗,那得修脚修到何年何月去了
(修脚就是字面意思,游戏里打下半身,一般说视野受限打不到上半身的情况所以修脚,在这里你可以理解为:
你把BOSS卡在一个角落,由于地形原因,他打不到你,然后你又只能打他的脚,但是你的伤害只有1,Boss有9999血)
零.引题
- # 为什么我们需要MVVM架构?
- # 如果不使用MVVM架构会产生什么问题?
复制代码
- 有人说MVVM架构是为了前后端分离,人不分离,
换句话说,也就是业务层和界面分离,做到互不干扰,
你也可以说是,将表现层和逻辑层分离,
- 但总的来说,其实就是为了解耦,你也不想我写个业务逻辑(界面),还得去搞明白前端(后端)怎么写的吧
- 所以为了避免业务逻辑和UI黏在一起,比强力粘鼠板还粘,于是MVVM架构诞生了
- MVVM将 界面、逻辑、数据 彻底拆开,终于不用测试的时候还要烧纸祈祷了(bushi
附赠博客园讲的比较通俗易懂的一篇文章:
为什么要用MVVM - maanshancss - 博客园
- 然后先来看几行简单的代码和超级简易的MVVM架构
- 这里实现了一个非常简单的功能:点击按钮之后跳出一个弹窗
但是会发现,事件交互逻辑和UI完完全全绑死了,
如果我后面想要复用这个控件或者在其他页面代码中复用对应的事件逻辑,怎么办呢
- <Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid>
复制代码- private void Button_Click(object sender, RoutedEventArgs e)
- {
- string accout = txtname.Text;
- MessageBox.Show($"{accout}");
- }
复制代码- # 交互逻辑
- 点击按钮
- ↓
- 读控件
- ↓
- 执行逻辑 # 事件Button_Click()
- ↓
- 完成交互 # 弹窗
复制代码
<ul>现在我们用MVVM来实现一下,不懂没关系,先留下一个简单的印象
- # 项目
- MVVM_Demo
- ├─ Views
- │ └─ MainWindow.xaml
- ├─ ViewModels # 数据
- │ └─ MainViewModel.cs
- └─ Commands
- └─ RelayCommand.cs
复制代码- 1.UI去掉 x:Name,绑定数据,引入数据ViewModel雏形
由于现在的代码逻辑过于依赖UI控件,所以我们需要将数据和UI解耦,你们不能在一起 她是你妹妹- // 现在
- string accout = txtname.Text;
- // 目标:实现UI和数据绑定
- // TextBox.Text ←→ Account
复制代码
- 1)代码中加入属性
- public string Account { get; set; }
复制代码
- 2)UI去掉 x:Name,绑定数据(这里以TextBox为例,Button同理)
然后,别问我为什么混入了两种语言的注释.....
- # 绑定 ViewModel<Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid>#<Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid>
复制代码
- 2.核心 — UI自动刷新:实现绑定更新(这里依旧以TextBox为例)
- public class MainViewModel : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler? PropertyChanged;
- // 绑定的数据
- private string _account = string.Empty;
- // 属性: get + set
- public string Account
- {
- get => _account;
- set
- {
- _account = value;
- OnPropertyChanged(nameof(Account));
- }
- }
- // 绑定更新
- void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- }
复制代码
- 3.事件改命令Command(再次提醒:⚠命令不是事件的上位替代!!!)
- 你问为什么要改啊,因为:MVVM 不允许 UI 调后台函数
- [/code]
- [*][code]public MainViewModel()
- {
- LoginCommand = new RelayCommand(Execute);
- }
- public ICommand LoginCommand { get; }
复制代码
附上完整示例代码:
如果下面你遇到一些看不懂的代码,不要慌不要急,因为啊,私密马赛我也看不懂
但是你要明白大致的内容和结构,不会的,随时随查
我才学C#几个月啊,我要是可以这么短时间可以纯手搓MVVM,我就是真的天赋狗了
MainWindow.xaml
- <Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid><Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid><Grid>
- <StackPanel>
- <TextBox x:Name="txtname"/>
- <Button Height="100" Width="100" Click="Button_Click" Content="登录"/>
- </StackPanel>
- </Grid>
复制代码
MainViewModel.cs
- using System.ComponentModel;
- using System.Windows;
- using System.Windows.Input;
- using MVVM_Demo.Commands;
- namespace MVVM_Demo.ViewModels
- {
- public class MainViewModel : INotifyPropertyChanged
- {
- public MainViewModel()
- {
- LoginCommand = new RelayCommand(ExecuteLogin, CanExecuteLogin);
- }
- public event PropertyChangedEventHandler? PropertyChanged;
- // 密码
- private string _account = string.Empty;
- public string Account
- {
- get => _account;
- set
- {
- _account = value;
- OnPropertyChanged(nameof(Account));
- // 通知按钮状态变化
- (LoginCommand as RelayCommand)?.RaiseCanExecuteChanged();
- }
- }
- // 登录绑定命令
- public ICommand LoginCommand { get; }
- // 执行登录
- private void ExecuteLogin(object? obj)
- {
- MessageBox.Show($"{Account}");
- }
- // 控制按钮是否可点
- private bool CanExecuteLogin(object? obj)
- {
- return !string.IsNullOrWhiteSpace(Account);
- }
- // 绑定更新
- void OnPropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
- }
- }
复制代码
- RelayCommand.cs
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Input;
- namespace MVVM_Demo.Commands
- {
- public class RelayCommand : ICommand
- {
- private readonly Action<object?> _execute;
- private readonly Func<object?, bool>? _canExecute;
- public event EventHandler? CanExecuteChanged;
- public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
- {
- _execute = execute;
- _canExecute = canExecute;
- }
- // 能否启用
- public bool CanExecute(object? parameter)
- {
- return _canExecute == null || _canExecute(parameter);
- }
- // 执行逻辑
- public void Execute(object? parameter) => _execute(parameter);
- // 手动刷新按钮状态
- public void RaiseCanExecuteChanged()
- {
- CanExecuteChanged?.Invoke(this, EventArgs.Empty);
- }
- }
- }
复制代码
<blockquote>
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |