2018-8-10-WPF-轻量级-MVVM-框架入门-2.1.2
title | author | date | CreateTime | categories |
---|---|---|---|---|
WPF 轻量级 MVVM 框架入门 2.1.2
|
lindexi
|
2018-08-10 19:16:51 +0800
|
2018-06-30 11:18:40 +0800
|
WPF mvvm
|
本文告诉大家如何使用本金鱼的 MVVM 轻量框架。
一个好的框架是不需要解释就可以让大家使用,但是本金鱼没有这个能力,所以就写了这个文章告诉大家如何使用。
本文的框架主要是简单,可以快速解耦 ViewModel 和 View 依赖,解耦 ViewModel 之间依赖,减少 ViewModel 的代码量。
具体的思想是使用消息发送的方法,多个 ViewModel 之间使用发送消息解除依赖。把原来很多需要写在 ViewModel 的代码通过发送指定的消息,在其他类处理,减少 ViewModel 代码。
下面来告诉大家如何使用这个框架。
首先是安装库
安装
首先需要从 Nuget 安装两个库
lindexi.wpf.Framework
lindexi.MVVM.Framework
第一个库是使用 wpf 的封装,因为我还有 UWP 的封装,实际上在使用,用 WPF 或 UWP 是差不多的。只要存在 UWP 和 WPF 不相同的库,我就把这写封装在不同的库。
因为 Nuget 可以找到依赖库,所以只需要安装 lindexi.wpf.Framework 就会自动安装 lindexi.MVVM.Framework 。如果现在使用的是 Xarmain ,那么安装 lindexi.MVVM.Framework 就可以,这个库使用 dotnet framework 4.5 和 dotnet standard 2.0 ,所以在很多项目都可以使用。
项目要求
安装这个库要求最低版本是 dotnet framework 4.5 以上,对于 dotnet framework 4.0 的项目无法使用。
创建主页面
和使用 win10 uwp 轻量级 MVVM 框架入门 2.1.5.3199 差不多,先创建一个项目,然后在这个项目的 MainWindow.xaml 放一个 Frame 作为跳转
创建 ViewModel 类,并且 MainWindow 在使用 ViewModel 属性,在 MainWindow 构造函数调用下面函数
ViewModel.OnNavigatedTo(this, frame);
这里的 frame 就是 MainWindow 创建的 Frame,需要在 ViewModel 类继承 NavigateViewModel ,然后写 OnNavigatedTo 代码
public override void OnNavigatedTo(object source, object e)
// 忽略代码 Content = new NavigateFrame((Frame) e);
这里可以看到 NavigateFrame 在 UWP 的框架和在 WPF 框架都存在,但是两个类的实现不相同。
这里设置 Content 可以让之后的页面进行导航。
找到 ViewModel
现在在创建的 ViewModel 推荐在 App.xaml 作为资源,因为 WPF 的页面跳转没有和 UWP 一样可以获得参数,需要通过自己的方式拿到。打开 App.xaml 在里面添加 ViewModel 作为静态属性
<Application x:Class="lindexi.Mvvm.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:lindexi.Mvvm"
StartupUri="MainWindow.xaml">
<Application.Resources>
<local:ViewModel x:Key="ViewModel"></local:ViewModel>
</Application.Resources>
</Application>
现在打开 MainWindow.xaml 绑定 DataContext
DataContext="{StaticResource ViewModel}"
在 MainWindow 的构造函数拿到 ViewModel ,需要强转
public MainWindow()
{
InitializeComponent();
ViewModel = (ViewModel) DataContext;
ViewModel.OnNavigatedTo(this, frame);
} public ViewModel ViewModel { get; set; }
这样在被跳转的页面就可以通过 var viewModel = ViewModel["xx"];
获得 ViewModel 。
通过附加属性找到 ViewModel
第二个方法是通过附加属性的方法找到 ViewModel ,因为在 WPF 是可以定义可继承的附加属性,而在 UWP 是不可以自己定义可以继承的附加属性。在 WPF 可以通过定义附加属性的方式让页面拿到上一级的 ViewModel ,那么两个方法的不同在哪?如果定义为资源,那么使用比较简单。如果定义为附加属性,可以在相同的 ViewModel 被不同的地方使用,支持一个程序有多个可跳转的 ViewModel 可以做出比较复杂的程序。
打开 MainWindow.xaml.cs 定义一个附加属性
public MainWindow()
{
InitializeComponent(); ViewModel = (ViewModel) GetValue(ViewModelProperty);
ViewModel.OnNavigatedTo(this, frame);
DataContext = ViewModel;
} public ViewModel ViewModel { get; set; } public static readonly DependencyProperty ViewModelProperty = DependencyProperty.RegisterAttached(
"ViewModel", typeof(NavigateViewModel), typeof(MainWindow),
new FrameworkPropertyMetadata(new ViewModel(), FrameworkPropertyMetadataOptions.Inherits));
这样被跳转的页面就可以通过附加属性拿到值,可以通过 var viewModel = ViewModel["xx"];
获得
跳转页面
现在来多创建两个页面 A 页面和 B 页面,并且创建两个页面的 ViewModel 添加到 ViewModel 的列表。
public class ViewModel : NavigateViewModel
{
/// <inheritdoc />
public override void OnNavigatedTo(object sender, object obj)
{
ViewModelPage = new List<ViewModelPage>()
{
new ViewModelPage(new NavigatableViewModel<AModel>(), new NavigatablePage<A>()),
new ViewModelPage(new NavigatableViewModel<BModel>(), new NavigatablePage<B>())
}; Content = new NavigateFrame((Frame) obj); Navigate("AModel", null);
} } public class AModel : ViewModelMessage
{
/// <inheritdoc />
public override void OnNavigatedFrom(object sender, object obj)
{
} /// <inheritdoc />
public override void OnNavigatedTo(object sender, object obj)
{
}
} public class BModel : ViewModelMessage
{
/// <inheritdoc />
public override void OnNavigatedFrom(object sender, object obj)
{
} /// <inheritdoc />
public override void OnNavigatedTo(object sender, object obj)
{
}
}
添加 ViewModel 到 ViewModelPage 的方法就是通过创建 ViewModelPage 合并,创建的时候提供两个方法,一个是输入 Type 的方法,另一个是泛型。输入 Type 的方法是用来反射,很少推荐使用。
修改 A 页面的背景,可以用来看到被跳转到 A 页面
本文使用的是上面的第一个方式拿到 ViewModel 所以需要在 A 页面添加一些代码获得 ViewModel 。
在 A 页面的 xaml 添加下面代码
DataContext="{Binding Source={StaticResource ViewModel},Path=[AModel]}"
这样就可以通过 NavigateViewModel["xx"]
的方法获得 ViewModel
跳转命令
可以看到在 A 页面有跳转按钮,点击这个按钮可以用来跳转到 B 页面
因为界面很简单,我就不告诉大家了。
打开 AModel 添加一个函数,在这个函数就是按钮点击下去调用的函数
Send(new NavigateMessage(this, nameof(BModel)));
从代码可以看到跳转到 B 页面只需要发送一个 NavigateMessage ,具体怎么跳转是不需要写的
自定义命令
现在可以尝试使用框架的用法,自己定义消息和处理
在 B 页面发送文字到 MainWindow 显示,不让 BModel 和 ViewModel 有耦合,减少在 BModel 和在 ViewModel 的代码。
如果 ViewModel 要让 MainWindows 显示文字,就需要在 ViewModel 添加属性
public string SawbelChaceredis
{
get => _sawbelChaceredis;
set
{
_sawbelChaceredis = value;
OnPropertyChanged();
}
} private string _sawbelChaceredis;
这个属性是我随意定义,因为也不知道这个属性叫什么
在 ViewModel 有特殊的属性,可以定义一个接口,表示这个 ViewModel 有 属性 SawbelChaceredis ,定义的代码
public interface ISawbelChaceredisModel : IViewModel
{
string SawbelChaceredis { get; set; }
}
在 MainWindow 绑定这个属性
<TextBlock Margin="10,200,10,10" Text="{Binding SawbelChaceredis,Mode=OneWay}" />
已经让 ViewModel 绑定了页面,这时的 ViewModel 和界面没有耦合
定义消息用来发送字符串到 ISawbelChaceredisModel ,定义的方法请看代码
public class TextMessage : Message
{
/// <inheritdoc />
public TextMessage(ViewModelBase source, string str) : base(source)
{
SawbelChaceredis = str;
Goal = new PredicateInheritViewModel(typeof(ISawbelChaceredisModel));
} public string SawbelChaceredis { get; }
}
定义的消息使用了 PredicateInheritViewModel 表示这个消息会发送到 ISawbelChaceredisModel ,如果没有找到 ISawbelChaceredisModel 就没有处理消息
定义了消息还需要定一个类告诉如何处理这个消息
public class SawbelChaceredisComposite : Composite
{
/// <inheritdoc />
public SawbelChaceredisComposite()
{
Message = typeof(TextMessage);
} /// <inheritdoc />
public override void Run(IViewModel source, IMessage message)
{
var viewModel = (ISawbelChaceredisModel) source;
viewModel.SawbelChaceredis = ((TextMessage) message).SawbelChaceredis;
}
}
定义了这个类就告诉哪个消息可以处理,在构造函数的代码。然后使用 Run 处理这个消息。因为 SawbelChaceredisComposite 和消息是耦合的,只有处理知道消息,所以这里可以转换 ViewModel 因为这时知道是哪个收到
这里的处理还可以继承Composite<T>
这里的泛型就是消息的类型,可以把上面的代码减小,不需要写构造函数
public class SawbelChaceredisComposite : Composite<TextMessage>
{
/// <inheritdoc />
protected override void Run(IViewModel source, TextMessage message)
{
var viewModel = (ISawbelChaceredisModel) source;
viewModel.SawbelChaceredis = message.SawbelChaceredis;
}
}
在 B 页面点击时,发送消息
public class BModel : ViewModelMessage
{
/// <inheritdoc />
public override void OnNavigatedFrom(object sender, object obj)
{
} /// <inheritdoc />
public override void OnNavigatedTo(object sender, object obj)
{
} public void SendText()
{
Send(new TextMessage(this, "欢迎来我博客 https://lindexi.github.io/lindexi/ 有很多无聊博客"));
}
}
通过发送消息就可以把消息发送到界面
代码:WPF 轻量级 MVVM 框架入门 2.1.2-CSDN下载
参见:
2018-8-10-WPF-轻量级-MVVM-框架入门-2.1.2的更多相关文章
- Farseer.net轻量级开源框架 入门篇:查询数据详解
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 删除数据详解 下一篇:Farseer.net轻量级开源框架 中级篇: Where条 ...
- Farseer.net轻量级开源框架 入门篇:使用前说明
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 框架性能测试 下一篇:Farseer.net轻量级开源框架 入门篇: 增.删.改. ...
- Farseer.net轻量级开源框架 入门篇:逻辑层的选择
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 入门篇:增.删.改.查操作演示 下一篇:Farseer.net轻量级开源框架 入门 ...
- Farseer.net轻量级开源框架 入门篇:分类逻辑层
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 缓存逻辑层 下一篇:Farseer.net轻量级开源框架 入门篇: 添加数据详解 ...
- Farseer.net轻量级开源框架 入门篇:添加数据详解
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 分类逻辑层 下一篇:Farseer.net轻量级开源框架 入门篇: 修改数据详解 ...
- Farseer.net轻量级开源框架 入门篇:修改数据详解
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 添加数据详解 下一篇:Farseer.net轻量级开源框架 入门篇: 删除数据详解 ...
- Farseer.net轻量级开源框架 入门篇:删除数据详解
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 修改数据详解 下一篇:Farseer.net轻量级开源框架 入门篇: 查询数据详解 ...
- Farseer.net轻量级开源框架 入门篇:Where条件的终极使用
导航 目 录:Farseer.net轻量级开源框架 目录 上一篇:Farseer.net轻量级开源框架 入门篇: 查询数据详解 下一篇:Farseer.net轻量级开源框架 中级篇: 事务的使用 ...
- 在WPF的MVVM框架中获取下拉选择列表中的选中项
文章概述: 本演示介绍怎样在WPF的MVVM框架中.通过数据绑定的方式获取下拉列表中的选中项.程序执行后的效果例如以下图所看到的: 相关下载(代码.屏幕录像):http://pan.baidu.com ...
- 轻量级MVVM框架 Stylet
这两天试了下Stylet框架,这个框架虽然很小,但是功能齐全,简化了很多MVVM的代码,比如Command,对Dialog,MessageBox都有很好的支持. 开源地址 https://github ...
随机推荐
- agc014F Strange Sorting
这套题比较简单,以为自己能够独立A掉D和E,或许就能自己A掉F,看来还真是想多了 题意:给一个$n$的全排列,每次操作把$max(a[1],a[2],...,a[i]) = a[i]$的记为$high ...
- drf模块及源码
drf中的APIView请求生命周期 APIView的as_view(局部禁用csrf) => 调用父类view中的as_view返回view()方法 => 自己的类调用自己的dispat ...
- 学习JDK1.8集合源码之--ArrayDeque
1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...
- ZooKeeper的分布式锁实现
分布式锁一般有三种实现方式: 1. 数据库乐观锁: 2. 基于Redis的分布式锁: 3. 基于ZooKeeper的分布式锁. 本篇博客将介绍第三种方式,基于Zookeeper实现分布式锁.虽然网上已 ...
- 3_58 csapp 第三版的答案
参考代码了http://blog.csdn.net/scf0920/article/details/77543294 3.58 看汇编写c代码 long decode(long x, long y,l ...
- Win7x64易语言调试进程无法退出
这是个历史问题,几乎所有的Win7x64机器上都会碰到这个问题 解决方法: 启动黑月重新编译器
- C# dataGridView_CellValueChanged事件
C# 输入完以后立即更新缓冲区(DataGridView CheckBox列checked变化后就触发CellValueChanged事件) 在DataGridView添加如下的事件( Current ...
- angular.module()创建、获取、注册angular中的模块
// 传递参数不止一个,代表新建模块;空数组代表该模块不依赖其他模块 var createModule = angular.module("myModule", []); // 只 ...
- java简单jdbc查询操作
所采用的mysql的数据库驱动版本:5.0.8 mysql-connector-java-5.0.8-bin.jar 程序结构图: 表结构: 创表sql: Create Table CREATE TA ...
- js中的深拷贝和浅拷贝2
所谓 深浅拷贝: 对于仅仅是复制了引用(地址),换句话说,复制了之后,原来的变量和新的变量指向同一个东西,彼此之间的操作会互相影响,为 浅拷贝. 而如果是在堆中重新分配内存,拥有不同的地址,但是值是一 ...