本文來自轉載
原文作者: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>());