框架:.NET Core 3.1
第三方类库:Caliburn.Micro
目录
一、MVVM模式
(一)MVVM是什么
MVVM是Model-View-ViewModel的缩写形式,它通常被用于WPF或Silverlight开发。
Model——可以理解为带有字段,属性的类。
View——可以理解为我们所看到的UI。
View Model在View和Model之间,起到连接的作用,并且使得View和Model层分离。View Model不仅仅是Model的包装,它还包含了程序逻辑,以及Model扩展,例如,如果Model中有一个公开属性不需要在UI上显示,此时我们可以不再View Model中去定义它。
MVVM有工具类概念吗?
1、第一种方法:封装一个dll库
2、第二种方法:添加一个Commons文件夹,放帮助类
3、第三种方法:直接将帮助方法写在ViewModel类中
(二)优劣势、适用场景
1、优势
(1)MVVM 模式充分利用了 WPF 的依赖属性、数据和命令绑定等机制,降低界面显示和逻辑代码之间的耦合度,容易维护,修改表现层的时候只修改VIEW,修改业务逻辑的时候只修改ViewModel扩展灵活,UI 设计师和程序开发者可更好的分工及协同工作。
(2)可重用性:可以把一些视图逻辑放在ViewModel层中,让很多View重用这些视图逻辑。
(3)MVVM最大的优势是编写前端逻辑非常复杂的页面,尤其是需要大量DOM操作的逻辑,利用MVVM可以极大地简化前端页面的逻辑。
2、劣势
(1)对于以展示为主的页面,例如,新闻,博客、文档等,不能使用MVVM展示数据,因为这些页面需要被搜索引擎索引,而搜索引擎无法获取使用MVVM并通过API加载的数据。
(2)MVVM会增加代码量
3、使用场景
需要SEO(Search Engine Optimization)的页面,不能使用MVVM展示数据。不需要SEO的页面,如果前端逻辑复杂,就适合使用MVVM展示数据,例如,工具类页面,复杂的表单页面,用户登录后才能操作的页面等等。
(三)三层架构与MVVM模式
二、WPF绑定机制
三、利用Caliburn.Micro实现MVVM架构
(一)启动器
MVVM架构要从ViewModel类启动而不是View类,所以要删除之前的启动代码重写启动器。启动器写一个即可
- 首先新建一个WPF工程MatchingDemo3,Targe framework 至少要选4.5版本
- 右击引用,使用Nuget 安装Caliburn.Micro类库
- 删除MainWindow.xaml 并且删除App.xaml的 StartupUri="MainWindow.xaml"
- 新建 Models 、ViewModels、 Views、Libs、Commons文件夹
- 在Views层中新建TestView.xaml
<Window x:Class="MatchingDemo3.Views.TestView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MatchingDemo3.Views" xmlns:cal="http://www.caliburnproject.org" mc:Ignorable="d" Title="TestView" Height="450" Width="800"> <!-- 这一句是 为下面的cal定义 xmlns:cal="http://www.caliburnproject.org"--> <Grid> <Canvas> <Button Name="buttonTest" Content="click me" Height="30" Width="100" cal:Message.Attach="[Event Click]=[Action MyClick()]"/> <!--绑定方法 cal:Message.Attach="[Event Click]=[Action MyClick()]"--> </Canvas> </Grid> </Window>
- 在ViewModels层中新建TestViewModel.cs(Caliburn.Micro的自动匹配功能需要我们遵循严格的命名规范,显示层必须命名为Views,ViewModel层必须命名为ViewModels,并且xaml文件必须以View结尾,ViewModel的cs文件必须以ViewModel结尾)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Caliburn.Micro; using System.Windows; namespace MatchingDemo3.ViewModels { class TestViewModel { public void MyClick() { MessageBox.Show("成功调用"); } } }
-
新建一个Bootstrapper类,继承BootstrapperBase
using Caliburn.Micro;//BootstrapperBase 需要引用 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MatchingDemo3.ViewModels; using System.Windows;//StartupEventArgs会用到 /*启动器 * 告诉程序先启动ViewModel,而不是默认的xaml */ public class Bootstrapper: BootstrapperBase { public Bootstrapper() { Initialize(); } protected override void OnStartup(object sender, StartupEventArgs e) { DisplayRootViewFor<ShellViewModel>(); } }
重写OnStartup方法,使用 DisplayRootViewFor<ShellViewModel>();指定启动的ViewModel,Caliburn.Micro可以根据xxxxViewModel对应xxxxView的协定,自动实例化View,Caliburn.Micro支持View First和ViewModel First两种方式来创建View。完全不用在View的后台代码中写DataContext=new xxxViewModel()代码,十分方便。
-
修改App.xaml ,加入如下红色代码,注意wpf中和sliverlight中,此处的写法是有区别的,官网给出的是sliverlight的写法
<Application x:Class="MatchingDemo3.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:MatchingDemo3" > <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary> <local:Bootstrapper x:Key="bootstrapper" /> </ResourceDictionary> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
(二)双向绑定
双向绑定需要做这个操作,做一次即可,代码固定的复制过去就行。
1、ViewModel类继承INotifyPropertyChanged类
2、输入这段代码
/// <summary>
/// 双向绑定
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (propertyName != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
(三)数据绑定
1、基本类型绑定
前台代码
<Label Content="{Binding LabelRipInputContent}"/>
后台代码
/// <summary>
/// RIP输入文件夹
/// </summary>
string _LabelRipInputContent = "请选择";
public string LabelRipInputContent
{
get { return _LabelRipInputContent; }
set
{
_LabelRipInputContent = value;
RaisePropertyChanged("LabelRipInputContent");
}
}
赋值
//LabelRipInputContent = "你需要赋的值";
2、集合绑定
前台代码
<ListBox
Name="ListBoxSourceFile"
Width="350"
MinWidth="350"
Height="200"
MinHeight="200"
MaxHeight="200"
Canvas.Left="10"
Canvas.Top="50"
ItemsSource="{Binding SourceFileList}"
SelectedValue="{Binding SourceFileSelectValue}"
>
后台代码
//第一种方式:用ObservableCollection封装,直接赋值即可,最后无需刷新
/// <summary>
/// 源文件列表
/// </summary>
private ObservableCollection<string> _SourceFileList = new ObservableCollection<string>();
public ObservableCollection<string> SourceFileList
{
get { return _SourceFileList; }
set
{
_SourceFileList = value;
RaisePropertyChanged("SourceFileList");
}
}
赋值
//SourceFileList.Add("你需要赋的值");
//第二种方式:用ObservableCollection之外的LIst或者对象封装,直接赋值之后,最后需要刷新
/// <summary>
/// 源文件列表
/// </summary>
private ObservableCollection<string> _SourceFileList = new ObservableCollection<string>();
public ObservableCollection<string> SourceFileList
{
get { return _SourceFileList; }
set
{
_SourceFileList = value;
RaisePropertyChanged("SourceFileList");
}
}
赋值
//SourceFileList.Add("你需要赋的值");
//SourceFileList = SourceFileList;//刷新
(四)行为绑定
1、名称绑定
前台代码
<Button
Name="ButtonAddFileDestination"
Height="30"
MinHeight="30"
MaxHeight="30"
Width="100"
MinWidth="100"
MaxWidth="100"
Canvas.Left="10"
Canvas.Top="10"
Content="添加文件"/>
后台代码
/// <summary>
/// 添加目标文件
/// </summary>
public void ButtonAddFileDestination()
{
//调用打开文件对话框
OpenFileDialog dialogFileDestination = new OpenFileDialog();
dialogFileDestination.ShowDialog();
if (dialogFileDestination.FileName.Length > 7)
//将用户选中的文件显示在列表中
FileDestinationList.Add(dialogFileDestination.FileName);
}
2、cal绑定
前台代码
<Button
Name="buttonTest"
Content="click me"
Height="30"
Width="100"
cal:Message.Attach="[Event Click]=[Action MyClick()]"/>
后台代码
public void MyClick()
{
MessageBox.Show("成功调用");
}