WPF框架---MvvmLight介绍

WPF框架---MvvmLight介绍

目录

[1. MvvmLight 框架准备](#1. MvvmLight 框架准备)

[2. MvvmLight 中的相关基类](#2. MvvmLight 中的相关基类)

[3. MvvmLight 中的数据绑定与通知](#3. MvvmLight 中的数据绑定与通知)

[a. 核心功能](#a. 核心功能)

[b. 关键方法与属性](#b. 关键方法与属性)

[c. 完整示例](#c. 完整示例)

[d. 高级用法](#d. 高级用法)

[4. MvvmLight 中的命令对象](#4. MvvmLight 中的命令对象)

[a. 命令对象的作用](#a. 命令对象的作用)

[b. 核心接口:ICommand](#b. 核心接口:ICommand)

[c. MvvmLight 中的 RelayCommand](#c. MvvmLight 中的 RelayCommand)

[d. 动态更新命令的可执行状态](#d. 动态更新命令的可执行状态)

[e. 高级用法](#e. 高级用法)

[5. Messenger 对象使用](#5. Messenger 对象使用)

[a. Messenger 的核心作用](#a. Messenger 的核心作用)

[b. MvvmLight 中的 Messenger 实现](#b. MvvmLight 中的 Messenger 实现)

[c. 基本使用场景](#c. 基本使用场景)

[d. 高级用法](#d. 高级用法)

[6. DispatcherHelper 对象使用](#6. DispatcherHelper 对象使用)

[7. SimpleIoc 对象使用](#7. SimpleIoc 对象使用)

[a. SimpleIoc 的核心作用](#a. SimpleIoc 的核心作用)

[b. 核心方法与属性](#b. 核心方法与属性)

[c. 基本使用步骤](#c. 基本使用步骤)

[d. 高级用法](#d. 高级用法)

[e. 与 ViewModelLocator 结合使用](#e. 与 ViewModelLocator 结合使用)

MvvmLight 框架准备

作用: 快速搭建 MVVM 架构的应用程序,简化数据绑定、命令和消息传递。

步骤 : 通过 NuGet 安装 MvvmLightLibs 包。

2. MvvmLight 中的相关基类

核心基类:

ViewModelBase: ViewModel 基类,实现 INotifyPropertyChanged。

cs

复制代码

public class MainViewModel : ViewModelBase

{

private string _name;

public string Name

{

get => _name;

set => Set(ref _name, value); // 自动触发 PropertyChanged

}

}

ObservableObject: 轻量级可观察对象。

RelayCommand: 命令对象基类。

3. MvvmLight 中的数据绑定与通知

a. 核心功能

ViewModelBase 继承自 ObservableObject,并实现了 INotifyPropertyChanged 接口,主要负责:

属性变更通知:当 ViewModel 的某个属性值发生变化时,自动通知 UI 更新。

简化代码 :通过 Set 方法简化属性定义,避免手动触发 PropertyChanged 事件。

设计模式支持 :提供静态属性 IsInDesignMode,用于区分代码是在设计时(如 Visual Studio 设计器)还是运行时执行。

b. 关键方法与属性

(1) Set(ref T field, T value, [CallerMemberName] string propertyName = null)

作用 :在属性的 set 方法中调用此方法,自动比较新旧值,若不同则更新字段并触发 PropertyChanged 事件。

示例:

cs

复制代码

private string _name;

public string Name

{

get => _name;

set => Set(ref _name, value); // 自动触发通知

}

(2)RaisePropertyChanged(string propertyName)

作用 :手动触发某个属性的 PropertyChanged 事件。

场景:当某个属性的值依赖于其他属性时,手动通知 UI 更新。

cs

复制代码

public string FullName => $"{FirstName} {LastName}";

private string _firstName;

public string FirstName

{

get => _firstName;

set

{

Set(ref _firstName, value);

RaisePropertyChanged(nameof(FullName)); // 通知 FullName 属性变化

}

}

(3) IsInDesignMode

作用:静态属性,判断当前代码是否在设计器(如 Visual Studio 或 Blend)中运行。

用途:在设计时提供假数据,避免调用真实服务或数据库。

cs

复制代码

public class MainViewModel : ViewModelBase

{

public MainViewModel()

{

if (IsInDesignMode)

Name = "Design Mode Sample"; // 设计器显示假数据

else

LoadRealData(); // 运行时加载真实数据

}

}

c. 完整示例

cs

复制代码

using GalaSoft.MvvmLight;

public class UserViewModel : ViewModelBase

{

private string _userName;

private int _age;

public string UserName

{

get => _userName;

set => Set(ref _userName, value);

}

public int Age

{

get => _age;

set => Set(ref _age, value);

}

// 计算属性(依赖其他属性)

public string UserInfo => $"{UserName} (Age: {Age})";

// 当 UserName 或 Age 变化时,手动通知 UserInfo 更新

protected override void OnPropertyChanged(string propertyName = null)

{

base.OnPropertyChanged(propertyName);

if (propertyName == nameof(UserName) || propertyName == nameof(Age))

RaisePropertyChanged(nameof(UserInfo));

}

}

d. 高级用法

(1)批量通知多个属性

通过 RaisePropertyChanged(null) 或指定空字符串,通知所有属性更新(慎用,可能影响性能):

cs

复制代码

public void ResetAllProperties()

{

_userName = "Default";

_age = 0;

RaisePropertyChanged(""); // 通知所有属性更新

}

(2) 继承与扩展

可继承 ViewModelBase 并添加通用逻辑(如日志记录、验证):

cs

复制代码

public abstract class CustomViewModelBase : ViewModelBase

{

protected void LogPropertyChange(string propertyName)

{

Debug.WriteLine($"属性 {propertyName} 已更新");

}

public override void RaisePropertyChanged(string propertyName = null)

{

base.RaisePropertyChanged(propertyName);

LogPropertyChange(propertyName);

}

}

4. MvvmLight 中的命令对象

a. 命令对象的作用

解耦 UI 与业务逻辑:将用户操作(如点击按钮)映射到 ViewModel 的方法。

控制可执行状态 :根据条件动态启用或禁用 UI 元素(例如按钮的 IsEnabled)。

支持参数传递:允许从 UI 传递参数到 ViewModel(如选中项的 ID)。

b. 核心接口:ICommand

所有命令对象均实现 System.Windows.Input.ICommand 接口,其定义如下:

cs

复制代码

public interface ICommand

{

event EventHandler CanExecuteChanged; // 通知命令可执行状态变化

bool CanExecute(object parameter); // 判断命令是否可执行

void Execute(object parameter); // 执行命令逻辑

}

c. MvvmLight 中的 RelayCommand

MvvmLight 提供 RelayCommand 和 RelayCommand 类,简化了 ICommand 的实现。

(1) 基本用法(无参数)

cs

复制代码

public class MainViewModel : ViewModelBase

{

public RelayCommand SaveCommand { get; }

public MainViewModel()

{

// 初始化命令:绑定方法 + 可执行条件

SaveCommand = new RelayCommand(SaveData, CanSave);

}

private void SaveData()

{

// 保存逻辑

}

private bool CanSave()

{

return !string.IsNullOrEmpty(Name); // 仅当 Name 非空时按钮可用

}

}

(2) 支持参数传递(RelayCommand

cs

复制代码

public RelayCommand FilterCommand { get; }

public MainViewModel()

{

FilterCommand = new RelayCommand(param => ApplyFilter(param), param => !string.IsNullOrEmpty(param));

}

private void ApplyFilter(string keyword)

{

// 根据关键字过滤数据

}

d. 动态更新命令的可执行状态

(1) 手动触发更新

当 CanExecute 依赖的属性变化时,调用 RelayCommand 的 RaiseCanExecuteChanged 方法:

cs

复制代码

private string _name;

public string Name

{

get => _name;

set

{

Set(ref _name, value);

SaveCommand.RaiseCanExecuteChanged(); // 触发重新检查 CanSave

}

}

(1) 自动触发更新

利用 ViewModelBase 的 Set 方法自动触发属性变更通知,无需手动调用 RaiseCanExecuteChanged:

cs

复制代码

private string _name;

public string Name

{

get => _name;

set => Set(ref _name, value); // Set 方法已自动触发 PropertyChanged

}

// CanSave 方法中依赖 Name 属性

private bool CanSave() => !string.IsNullOrEmpty(Name);

e. 高级用法

(1) 异步命令

直接在命令中执行异步操作时,需注意线程安全(通过 DispatcherHelper):

cs

复制代码

public RelayCommand LoadDataCommand { get; }

public MainViewModel()

{

LoadDataCommand = new RelayCommand(async () => await LoadDataAsync());

}

private async Task LoadDataAsync()

{

try

{

IsLoading = true;

var data = await _dataService.GetData();

// 更新 UI(确保在 UI 线程)

DispatcherHelper.CheckBeginInvokeOnUI(() => DataList = data);

}

finally

{

IsLoading = false;

}

}

(2) 复合命令

将多个命令组合成一个逻辑操作:

cs

复制代码

public RelayCommand SubmitAllCommand { get; }

public MainViewModel()

{

SubmitAllCommand = new RelayCommand(() =>

{

SaveCommand.Execute(null);

LogCommand.Execute(null);

}, () => SaveCommand.CanExecute(null) && LogCommand.CanExecute(null));

}

(3) 命令的泛型约束

cs

复制代码

public RelayCommand DeleteItemCommand { get; }

public MainViewModel()

{

DeleteItemCommand = new RelayCommand(id => DeleteItem(id), id => id > 0);

}

private void DeleteItem(int itemId)

{

// 删除指定 ID 的项

}

5. Messenger 对象使用

在 MVVM 模式 中,Messenger 是一个用于实现 松耦合通信 的核心组件,尤其在 MvvmLight 框架 中被广泛使用。它允许不同组件(如 ViewModel、View、服务)之间通过消息进行通信,而无需直接引用彼此,从而降低依赖、提升代码可维护性。

a. Messenger 的核心作用

解耦组件通信:组件无需持有对方引用,通过消息订阅/发布机制交互。

跨层级传递数据:例如从子 ViewModel 通知父 ViewModel,或跨页面传递状态。

支持复杂场景:如广播通知、请求-响应模式、事件聚合等。

b. MvvmLight 中的 Messenger 实现

MvvmLight 的 Messenger 类是一个静态单例(Messenger.Default),提供消息的注册、发送和注销功能。其核心方法如下:

|-----------------------------------------------------------------|-------------------------------------------------------|

| 方法 | 作用 |

| Register(object recipient, Action action) | 订阅类型为 TMessage 的消息。recipient 为接收者标识(通常为 this )。 |

| Send(TMessage message) | 发送一条 TMessage 类型的消息,所有订阅者会收到通知。 |

| Unregister(object recipient) | 注销某个接收者的所有消息订阅,避免内存泄漏。 |

c. 基本使用场景

(1) 发送简单通知消息

场景:ViewModel A 完成数据加载后,通知 ViewModel B 刷新界面。

发送消息方:

cs

复制代码

// 发送一个无参数通知

Messenger.Default.Send(new NotificationMessage("DataLoaded"));

接收消息方(ViewModel B):

cs

复制代码

public ViewModelB()

{

// 注册接收 NotificationMessage 类型的消息

Messenger.Default.Register(this, message =>

{

if (message.Notification == "DataLoaded")

{

RefreshData();

}

});

}

(2) 传递数据对象

场景:用户选择某条数据后,跨页面传递选中项。

定义消息类型:

cs

复制代码

public class ItemSelectedMessage

{

public int ItemId { get; set; }

public ItemSelectedMessage(int id) => ItemId = id;

}

发送方:

cs

复制代码

// 用户选择某项后发送消息

Messenger.Default.Send(new ItemSelectedMessage(selectedItem.Id));

接收方:

cs

复制代码

Messenger.Default.Register(this, message =>

{

LoadItemDetails(message.ItemId); // 根据 ItemId 加载详情

});

d. 高级用法

(1) 消息令牌(Token)

作用:区分相同消息类型的不同用途,避免消息冲突。

发送带令牌的消息:

cs

复制代码

// 发送消息时指定令牌

Messenger.Default.Send(

new NotificationMessage("UpdateChart"),

"ChartToken" // 令牌标识

);

接收指定令牌的消息:

cs

复制代码

Messenger.Default.Register(

this,

message => UpdateChartData(),

"ChartToken" // 仅接收带有此令牌的消息

);

(2) 泛型消息

场景:传递强类型数据,避免类型转换。

定义泛型消息:

cs

复制代码

public class GenericMessage

{

public T Content { get; }

public GenericMessage(T content) => Content = content;

}

发送泛型消息:

cs

复制代码

var data = new List();

Messenger.Default.Send(new GenericMessage>(data));

接收泛型消息:

cs

复制代码

Messenger.Default.Register>>(this, message =>

{

UserList = message.Content; // 直接获取 List

});

(3) 双向通信(请求-响应模式)

场景:ViewModel A 请求数据,ViewModel B 响应返回结果。

发送请求消息:

cs

复制代码

public class DataRequestMessage

{

public Action Callback { get; set; } // 定义回调委托

}

// 发送请求,并注册回调

Messenger.Default.Send(new DataRequestMessage

{

Callback = response => HandleResponse(response)

});

接收请求并响应:

cs

复制代码

Messenger.Default.Register(this, message =>

{

var data = FetchDataFromService(); // 获取数据

message.Callback?.Invoke(data); // 执行回调

});

6. DispatcherHelper 对象使用

作用: 在非 UI 线程更新 UI。

初始化:

cs

复制代码

DispatcherHelper.Initialize(); // 在 App.xaml.cs 中调用

使用:

cs

复制代码

Task.Run(() =>

{

// 后台线程操作

DispatcherHelper.CheckBeginInvokeOnUI(() =>

{

// 更新 UI 元素

StatusText = "Processing...";

});

});

7. SimpleIoc 对象使用

SimpleIoc 是 MvvmLight 框架中提供的一个轻量级依赖注入(Dependency Injection, DI)容器,用于管理应用程序中各个组件(如 ViewModel、服务、数据源)的依赖关系。它通过 控制反转(IoC) 和 依赖注入 机制,帮助开发者实现代码解耦、提高可测试性和可维护性。

a. SimpleIoc 的核心作用

解耦组件依赖:将类的依赖关系从代码中抽离,通过容器统一管理。

单例生命周期管理:默认以单例模式提供实例,避免重复创建对象。

简化实例获取:通过接口或类型直接获取已注册的实例。

支持构造函数注入:自动解析构造函数参数,完成依赖注入。

b. 核心方法与属性

以下是 SimpleIoc 的常用方法及其功能:

|----------------------------------|------------------------------------|

| 方法/属性 | 作用 |

| Register() | 注册接口 TInterface 和其实现类 TClass 。 |

| Register() | 直接注册类型 TClass (无接口)。 |

| GetInstance() | 获取类型 T 的实例(已注册的接口或类)。 |

| ContainsCreated() | 检查类型 T 的实例是否已被创建。 |

| Reset() | 重置容器,清空所有注册和实例(用于测试或重新初始化)。 |

| IsRegistered() | 检查类型 T 是否已注册。 |

c. 基本使用步骤

(1) 注册服务与 ViewModel

在应用程序启动时(如 ViewModelLocator 或 App.xaml.cs 中),注册所有依赖项:

cs

复制代码

public class ViewModelLocator

{

public ViewModelLocator()

{

// 注册服务(接口 + 实现类)

SimpleIoc.Default.Register();

// 注册 ViewModel(无接口)

SimpleIoc.Default.Register();

}

// 提供 ViewModel 实例的公共属性

public MainViewModel Main => SimpleIoc.Default.GetInstance();

}

(2) 获取实例

通过 GetInstance 方法获取已注册的实例:

cs

复制代码

// 获取 ViewModel 实例

var mainVM = SimpleIoc.Default.GetInstance();

// 获取服务实例

var dataService = SimpleIoc.Default.GetInstance();

(3) 构造函数注入

当注册的类(如 ViewModel)依赖其他服务时,SimpleIoc 会自动解析构造函数参数:

cs

复制代码

public class MainViewModel : ViewModelBase

{

private readonly IDataService _dataService;

// 构造函数依赖注入:自动传入已注册的 IDataService 实例

public MainViewModel(IDataService dataService)

{

_dataService = dataService;

}

}

d. 高级用法

(1) 单例模式 vs. 瞬时模式

单例模式(默认):整个应用程序生命周期内只创建一个实例。

cs

复制代码

// 默认单例模式

SimpleIoc.Default.Register();

瞬时模式 :每次调用 GetInstance 时创建新实例。

cs

复制代码

SimpleIoc.Default.Register(createInstanceImmediately: false);

var service = SimpleIoc.Default.GetInstance(); // 每次返回新实例

(2) 手动指定实例

允许直接注册一个已存在的对象实例:

cs

复制代码

var logger = new FileLogger();

SimpleIoc.Default.Register(() => logger); // 注册现有实例

(3) 依赖覆盖

在测试中,可以替换实现类以注入 Mock 对象:

cs

复制代码

// 生产环境注册真实服务

SimpleIoc.Default.Register();

// 测试环境覆盖为 Mock 服务

SimpleIoc.Default.Unregister();

SimpleIoc.Default.Register();

e. 与 ViewModelLocator 结合使用

ViewModelLocator 是 MvvmLight 中用于集中管理 ViewModel 的类,通常与 SimpleIoc 配合使用,通过 XAML 绑定 ViewModel。

(1) 定义 ViewModelLocator

cs

复制代码

public class ViewModelLocator

{

public ViewModelLocator()

{

// 注册服务和 ViewModel

SimpleIoc.Default.Register();

SimpleIoc.Default.Register();

}

// 暴露 ViewModel 属性供 XAML 绑定

public MainViewModel Main => SimpleIoc.Default.GetInstance();

}

(2) 在 XAML 中声明资源

在 App.xaml 中合并 ViewModelLocator:

cs

复制代码

(3) 在 View 中绑定 ViewModel

cs

复制代码

DataContext="{Binding Main, Source={StaticResource Locator}}">

相关推荐

《魔兽世界》怀旧服龟壳掉落位置
全新升级!SHIMANO 2024 STRADIC SW 海水纺车轮
镗削加工:定义、过程、用途和类型
《半夏流年》相关文章
qq空间转载到微信朋友圈
如何在2025年端午节亲手制作香囊与粽子?4大步骤让你成手工达人!
《武装突袭3》arma3怎么上车?
小米电视设置在哪打开 小米电视设置界面打开方法
舌尖上的中國精選圖一