本文来自转载
原文作者:RyzenAdorer
原文标题:.NET Core 3 WPF MVVM 框架 Prism 系列之数据绑定
原文链接:https://www.cnblogs.com/ryzen/p/11905866.html
一. 安装 Prism
- 使用程序包管理控制台
Install-Package Prism.Unity -Version 7.2.0.1367
也可以去掉‘-Version 7.2.0.1367’获取最新的版本
- 使用管理解决方案的 Nuget 包
在上面或许我们有个疑问?为啥安装 prism 会跟 Prism.Unity 有关系,我们知道 Unity 是个 IOC 容器, 而 Prism 本身就支持 IOC, 且目前官方支持几种 IOC 容器:
-
- 且 unity 由于是微软官方的,且支持 prism 的组件化,由此我推荐使用 prism.unity,在官方文档中 prism7 不支持 prism.Mef,Prism 7.1 将不支持 prism.Autofac
-
- 安装完 prism.unity 就已经包含着所有 prism 的核心库了,架构如下:
二. 实现数据绑定
我们先创建 Views 文件夹和 ViewModels 文件夹,将 MainWindow 放在 Views 文件夹下,再在 ViewModels 文件夹下面创建 MainWindowViewModel 类,如下:
xaml 代码如下:
<Window
x:Class="PrismSample.Views.MainWindow"
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:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:PrismSample"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800"
prism:ViewModelLocator.AutoWireViewModel="True"
>
<StackPanel>
<TextBox
Text="{Binding Text}"
Margin="10"
Height="100"
FontSize="50"
Foreground="Black"
BorderBrush="Black"
/>
<button
Height="100"
Width="300"
Content="Click Me"
FontSize="50"
Command="{Binding ClickCommnd}"
/>
</StackPanel>
</Window>
ViewModel 代码如下:
using Prism.Commands;
using Prism.Mvvm;
namespace PrismSample.ViewModels
{
public class MainWindowViewModel:BindableBase
{
private string _text;
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
private DelegateCommand _clickCommnd;
public DelegateCommand ClickCommnd =>
_clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));
void ExecuteClickCommnd()
{
this.Text = "Click Me!";
}
public MainWindowViewModel()
{
this.Text = "Hello Prism!";
}
}
}
启动程序:
点击 click Me 按钮:
可以看到,我们已经成功的用 prism 实现数据绑定了,且 View 和 ViewModel 完美的前后端分离
但是现在我们又引出了另外一个问题,当我们不想按照 prism 的规定硬要将 View 和 ViewModel 放在 Views 和 ViewModels 里面,又或许自己的项目取名规则各不相同怎么办,这时候就要用到另外几种方法:
- 更改命名规则
如果,公司命名规则很变态,导致项目结构变成这样(这种公司辞职了算了):
首先我们在 App 需要引入 prism,修改‘Application’为‘prism:PrismApplication’且删除 StartupUri
xaml 代码如下:
<prism:PrismApplication
x:Class="PrismSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:local="clr-namespace:PrismSample"
>
<Application.Resources> </Application.Resources>
</prism:PrismApplication>
cs 后台代码如下:
using Prism.Unity;
using Prism.Ioc;
using Prism.Mvvm;
using System.Windows;
using PrismSample.Viewsb;
using System;
using System.Reflection;
namespace PrismSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : PrismApplication
{
//设置启动起始页
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
}
//配置规则
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}Test, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
}
}
上面这两句是关键:
".Viewsb." 表示 View 所在文件夹 namespace,".ViewModelsa.OhMyGod." 表示 ViewModel 所在 namespace
var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
Test 表示 ViewModel 后缀
var viewModelName = $"{viewName}Test, {viewAssemblyName}";
- 自定义 ViewModel 注册
我们新建一个 Foo 类作为自定义类,代码如下:
using Prism.Commands;
using Prism.Mvvm;
namespace PrismSample
{
public class Foo:BindableBase
{
private string _text;
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value); }
}
public Foo()
{
this.Text = "Foo";
}
private DelegateCommand _clickCommnd;
public DelegateCommand ClickCommnd =>
_clickCommnd ?? (_clickCommnd = new DelegateCommand(ExecuteClickCommnd));
void ExecuteClickCommnd()
{
this.Text = "Oh My God!";
}
}
}
修改 App.cs 代码:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.Register<MainWindow, Foo>();
//ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
//{
// var viewName = viewType.FullName.Replace(".Viewsb.", ".ViewModelsa.OhMyGod.");
// var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
// var viewModelName = $"{viewName}Test, {viewAssemblyName}";
// return Type.GetType(viewModelName);
//});
}
运行:
点击按钮:
就算是不注释修改命名规则的代码,我们发现运行结果还是一样,因此我们可以得出结论,
这种直接的,不通过反射注册的自定义注册方式优先级会高点,在官方文档也说明这种方式效率会高点
且官方提供 4 种方式,其余三种的注册方式如下:
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), typeof(MainWindowTest));
ViewModelLocationProvider.Register(typeof(MainWindow).ToString(), () => Container.Resolve<Foo>());
ViewModelLocationProvider.Register<MainWindow>(() => Container.Resolve<Foo>());