【MVVM Light】新手初识MVVM,你一看就会
一、前言
作为一个初入软件业的新手,各种设计模式与框架对我是眼花缭乱的。所以当我接触到这些新知识的时候就希望自己能总结几个步骤,以便更好更方便的在日常工作中进行使用。
MVVM顾名思义就是Model-View-View Model的缩写。老司机们一直说绑定绑定,我就纳闷了View是展示,Model是模型,那View Model怎么写处理的逻辑呢?它是如何将Model和View联系到一起的呢?这是我第一次听到MVVM时产生的疑惑。经过了一些编程经历,大致明白了整个过程。本文不会过分强调MVVM中一些特别深入的技术(我暂时也没那本事),只是从一个初学者的角度去学会如何最快速的使用MVVM。
本文将以MVVM Light作为例子,因为它是个轻量化的MVVM框架,非常方便使用。以后会逐步介绍些其他的MVVM框架,如DevExpress的等等。知识是互通的,明白了其中一个,另一种也差不多不离其宗了。
二、准备
下载MVVM Light的方式多种多样,可以使用NuGet包管理器或者直接登录官网,一搜就找到了。
本项目安装完MVVM Light后可以看到引用:

还有一个ViewModel文件夹:

三、MVVM
假设我们有这样一个产品的Model:IsChecked属性大家一看就知道是用于在前端与CheckBox有联系而设置的属性。
namespace StudyMVVM
{
public class ProductInfo
{
public bool IsChecked { get; set;}
public string ProductName { get; set; }
public string ProductIcon { get; set; }
public string ProductUrl { get; set; }
public string OldVersion { get; set; }
public string NewVersion { get; set; }
}
}
假设我们有一个WPF页面MainView.xaml,也就是View是这么写的:首先别管那个 ItemsSource,下面会慢慢说到
<Grid Name="GridName" Grid.Row="" Margin="30,5" >
<ListBox Name="lb_Update" VerticalAlignment="Center" Height="" ItemsSource="{Binding UpdateProducts}" Margin="0,6,0,10"></ListBox>
</Grid>
那么我们想要把多个对象的属性填充到一个ListBoxItem里,然后将若干个ListBoxItem放到ListBox里,所以:
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Width="" Height="" MaxHeight="" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22*"/>
<ColumnDefinition Width="32*"/>
<ColumnDefinition Width="68*"/>
<ColumnDefinition Width="100*"/>
<ColumnDefinition Width="154*"/>
<ColumnDefinition Width="105*"/>
<ColumnDefinition Width="29*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions> <Grid Grid.Column="" Grid.RowSpan="">
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsChecked}"/>
</Grid> <Grid Grid.Column="" Grid.RowSpan="">
<Image Source="{Binding ProductIcon}" Width=""></Image>
</Grid> <Grid Grid.Column="" Grid.RowSpan="">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="" Text="{Binding ProductName}"/>
</Grid> <Grid Grid.Column="" Grid.Row="">
<TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="0,0,0,5" Text="{Binding OldVersion}"/>
</Grid> <Grid Grid.Column="" Grid.Row="">
<TextBlock VerticalAlignment="top" HorizontalAlignment="Center" Margin="0,5,0,0" Text="{Binding NewVersion}"/>
</Grid> <Grid Grid.Column="" Grid.RowSpan="">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">
<Hyperlink NavigateUri="{Binding ProductUrl}" Click="Hyperlink_Click">日志</Hyperlink>
</TextBlock>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我们可以非常清楚的看到Model中的属性都绑定到了View中!下面就是很关键的ViewModel了,我们还没用到上述的ItemsSource呢。
在MainViewModel.cs中,是这样的:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.IO;
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Diagnostics; namespace StudyMVVM.ViewModel
{
public class MainViewModel : ViewModelBase
{
public List<ProductInfo> UpdateProducts { get; set; } //
public MainViewModel()
{
UpdateProducts = new List<ProductInfo>();
for(int i=;i<;i++)
{
ProductInfo productinfo = new ProductInfo();
productinfo.IsChecked = true;
productinfo.ProductName = str_Name;
productinfo.ProductIcon = str_Path;
productinfo.ProductUrl = "www.baidu.com";
productinfo.OldVersion = "0.0.1";
productinfo.NewVersion = "0.0.2";
UpdateProducts.Add(productinfo);
}
}
}
}
这样,多个ProductInfo的对象被包装在名为UpdateProducts内,并且通过ItemsSource绑定到ListBox中,数据就这样填充上了。
四、如何写事件
当你在前端有个按钮,想处理若干个ListBoxItem,比如下载所有Checked为true的对象,你是否会怀念Winform的Click事件? 当然WPF也有Click事件。既然你已经用了MVVM,那么请少用,最好不用Click事件去处理这些东西,特别是你要写的事件是与你的ItemsSource所绑定的东西相关的。
说白了,在例子里就是和UpdateProducts有关系的,你就别用Click了。
在View中假设有一个Button:它的Command绑定了GetCheckedUpdateProducts事件
<Grid Name="UpdateBtn" Grid.Row="" Grid.Column="">
<Button Name="btn_update" Width="" Height="" Cursor="Hand" Content="更新" Foreground="White" FontSize="" Command="{Binding GetCheckedUpdateProducts}">
</Grid>
在ViewModel中,注意引用GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
namespace StudyMVVM.ViewModel
{
public class MainViewModel : ViewModelBase
{
public RelayCommand GetCheckedUpdateProducts { get; set; } public MainViewModel()
{
this.GetCheckedUpdateProducts = new RelayCommand(GetProducts);
}
} private void GetProducts()
{
//Your Button Command: Download checked products
}
}
将真正的事件逻辑GetProducts()赋值给RelayCommand GetCheckedUpdateProducts,前端通过Command=“{Binding GetCheckedUpdateProducts}” 即可。
五、RaisePropertyChanged
这个RaisePropertyChanged是专门来照顾没妈妈(ItemsSource)的孩子的(properties)。
假设xaml前端有一个进度条,当你按下按钮下载checked=true的产品时,进度条要实时显示下载情况:
<ProgressBar Grid.Row="" Height="" VerticalAlignment="Top" Margin="10,0,8,0" Maximum="{Binding MaxValue}" Minimum="{Binding MinValue}" Value="{Binding ProgressValue}"/>
Maximum和Minimum一般是个定值,但ProgressValue是变化的,并且和Model里属性字段的没半毛钱的关系啊,咋办?我得告诉View我在改变啊,那么在ViewModel中:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command; namespace StudyMVVM.ViewModel
{
public class MainViewModel : ViewModelBase
{
public int MaxValue { get; set; }
public int MinValue { get; set; }
public int ProgressValue { get; set; }
public RelayCommand GetCheckedUpdateProducts { get; set; }
public MainViewModel()
{
MaxValue = ;
MinValue = ;
ProgressValue = ;
this.GetCheckedUpdateProducts = new RelayCommand(GetProducts);
} private void GetProducts()
{
BackgroundWorker bgWorker = new BackgroundWorker();
bgWorker.DoWork += new DoWorkEventHandler(worker_Dowork);
bgWorker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
bgWorker.RunWorkerAsync();
}
void worker_Dowork(object sender, DoWorkEventArgs e)
{
//do work
} void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
UpdateMessage = (string)e.UserState;
ProgressValue = e.ProgressPercentage; RaisePropertyChanged(() => ProgressValue); // I'm Here!!!! Hey! Look At Me !
RaisePropertyChanged(() => UpdateMessage);
} void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result is Exception)
{
UpdateMessage = (e.Result as Exception).Message;
}
else
{
UpdateMessage = (string)e.Result;
}
}
}
}
PS:上述代码还用到了BackgroundWorker,这是一个不错的异步显示进度条的控件,有兴趣的可以试试,非常方便使用。
六、DataContext
看到这里,有些新手觉得ViewModel中的东西可以很顺利成章的绑定到View上了,错!不觉得奇怪吗?凭什么这个MainViewModel就要和上述的View建立联系,而不是和其他的View有联系呢?
为了防止View上错老婆(为什么我不说防止ViewModel找到隔壁老王呢?各位可以思考想想),我们需要在某一个View中指定其DataContext是哪个ViewModel!
using YourProject.ViewModel;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Diagnostics; namespace StudyMVVM
{
/// <summary>
/// MainView.xaml 的交互逻辑
/// </summary>
public partial class MainView : Window
{
public MainView()
{
this.DataContext = new MainViewModel();// find correct wife
}
}
}
还有一个办法能指定DataContext,MVVM Light提供了ViewModelLocator.cs来帮助你绑定view的DataContext;Xaml里也可以绑定DataContext。不过我还是喜欢用上述最原始的方法。至于ViewModelLocator怎么使用,博园有相当多的牛人及文章,想要深入了解的可以去搜下。
其实DataContext在你引入MVVM框架之后就应该进行绑定了,写在这里只是为了提醒大家其重要性!
七、大结局
终于写完了,科科,摆了个白!
【MVVM Light】新手初识MVVM,你一看就会的更多相关文章
- MVVM Light 新手入门(1):准备阶段
1.新建WPF空白项目. 2.NuGet 程序包中安装 3.根据MVVM分层结构,建立包含Model.View.ViewModel三层文件夹 如图: 1.View负责前端展示,与ViewModel进行 ...
- MVVM Light 新手入门(3) :ViewModel / Model 中定义“事件” ,并在View中调用 (无参数调用)
今天学习MVVM架构中“事件”的添加并调用,特记录如下,学习资料均来自于网络,特别感谢翁智华 的 利刃 MVVMLight 6:命令基础 在MVVM Light框架中,事件是WPF应用程序中UI与后台 ...
- MVVM Light 新手入门(2) :ViewModel / Model 中定义“属性” ,并在View中调用
今天学习MVVM架构中“属性”的添加并调用,特记录如下,学习资料均来自于网络,特别感谢翁智华的利刃 MVVMLight系列. 一个窗口的基本模型如下: View(视图) -> ViewModel ...
- Mvvm Light Toolkit 入门
原文:Mvvm Light Toolkit 入门 前言 之前学习UWP的时候就一直看到有关MVVM的资料但是一直没有系统的去学,最近正好有时间,特地来攻破这个点,顺便学习一下VS与GitHub的链接和 ...
- MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(导航)
系列一:看的迷迷糊糊的 一.Mvvm Light Toolkit for wpf/silverlight系列之准备工作 二.Mvvm Light Toolkit for wpf/silverlight ...
- 【MVVM Light】Messager的使用
一.前言 在MVVM编程的模式中,有时候我们会遇到一个很尴尬的情况: 若干个xaml.cs都复用一个ViewModel,当ViewModel想传递一个特定的消息给某一个xaml.cs的时候 ...
- Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架
Mvvm Light Toolkit for WPF/Silverlight系列之搭建mvvmlight开发框架 本章节,我将通过示例介绍如何搭建mvvmlight开发环境.示例中的我会针对wpf ...
- MVVM Light Toolkit使用指南
原文:MVVM Light Toolkit使用指南 原文地址: https://blog.csdn.net/ldld1717/article/details/77040077 概述 MVVM Lig ...
- WPF学习12:基于MVVM Light 制作图形编辑工具(3)
本文是WPF学习11:基于MVVM Light 制作图形编辑工具(2)的后续 这一次的目标是完成 两个任务. 本节完成后的效果: 本文分为三个部分: 1.对之前代码不合理的地方重新设计. 2.图形可选 ...
随机推荐
- 使用EF取数据库返回的数据
目录 一.取oracle自定义函数返回的自定义类型. 一.取oracle自定义函数返回的自定义类型. 1.首先创建一个函数返回自定义类型集合 --1.建立自定义类型 CREATE OR REPLACE ...
- ABP理论学习之导航(Navigation)
返回总目录 本篇目录 创建菜单 注册导航提供者 展示菜单 每一个web应用在页面之间都有一些要导航的菜单.ABP提供了公用的基础设施来创建菜单并将菜单展示给用户. 创建菜单 一个应用可能由不同的模块组 ...
- (C#)使用NPOI导出Excel
在做业务型的软件时,经常需要将某些数据导出,本文介绍了在Winform或Asp.net中使用NPOI(POI 项目的 .NET 版本)来操作Excel文件,而无需安装Office. 首先,需要获取NP ...
- 人生苦短,我用python——当我在玩python的时候我玩些什么
文章背景 家里的第一台电脑是在2006年夏天买的,10年上大学之后基本上就没人用,过没两年就当二手卖给一个熟人. 弟弟小我10岁,今年刚上初一.他在我毕业前半年就整天用妈妈的手机发短信给我,问我什么时 ...
- cache4j轻量级java内存缓存框架,实现FIFO、LRU、TwoQueues缓存模型
简介 cache4j是一款轻量级java内存缓存框架,实现FIFO.LRU.TwoQueues缓存模型,使用非常方便. cache4j为java开发者提供一种更加轻便的内存缓存方案,杀鸡焉用EhCac ...
- innerHTML,outerHTML,innerText,outerText区别以及insertAdjacentHTML()方法
在需要给文档插入大量的新的HTML标记的情况下,通过多次DOM操作先创建节点再指定它们之间的关系会非常麻烦而且效率不高,相对而言插入标记的方法会更加简单,速度也更快. 插入标记中有这四个属性inner ...
- Objective-C 工厂模式(下) -- 抽象工厂模式
相比简单工厂模式, 只有一个工厂 能生产的手机也是固定的 抽象工厂模式类似于有很多家工厂, 当用户要买什么手机就创建对应的工厂去生产 比如用户要买iPhone就创建一个Apple工厂来生产手机, 要买 ...
- for 循环打印图形
public class For { public static void main(String[] args) { //"使用双层for循环打印图形时,外层管行,内层管列",那 ...
- iOS开发-应用崩溃日志揭秘(一)
作为一名应用开发者,你是否有过如下经历? 为确保你的应用正确无误,在将其提交到应用商店之前,你必定进行了大量的测试工作.它在你的设备上也运行得很好,但是,上了应用商店后,还是有用户抱怨会闪退 ! 如果 ...
- iOS-常用的第三方框架的介绍
写iOS 程序的时候往往需要很多第三方框架的支持,可以大大减少工作量,讲重点放在软件本身的逻辑实现上. GitHub 里面有大量优秀的第三方框架,而且 License 对商业很友好.一下摘录一下几乎每 ...