.NET Core 3 WPF MVVM框架 Prism系列之資料繫結
阿新 • • 發佈:2019-11-21
一.安裝Prism
1.使用程式包管理控制檯
Install-Package Prism.Unity -Version 7.2.0.1367也可以去掉‘-Version 7.2.0.1367’獲取最新的版本
2.使用管理解決方案的Nuget包
在上面或許我們有個疑問?為啥安裝prism會跟Prism.Unity有關係,我們知道Unity是個IOC容器,而Prism本身就支援IOC,且目前官方支援幾種IOC容器:
1.且unity由於是微軟官方的,且支援prism的元件化,由此我推薦使用prism.unity,在官方文件中prism7不支援prism.Mef,Prism 7.1將不支援prism.Autofac 2.安裝完prism.unity就已經包含著所有prism的核心庫了,架構如下:
二.實現資料繫結
我們先建立Views資料夾和ViewModels資料夾,將MainWindow放在Views資料夾下,再在ViewModels資料夾下面建立MainWindowViewModel類,如下:
xmal程式碼如下:
<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裡面,又或許自己的專案取名規則各不相同怎麼辦,這時候就要用到另外幾種方法:
1.更改命名規則
如果,公司命名規則很變態,導致專案結構變成這樣(這種公司辭職了算了):
首先我們在App需要引入prism,修改‘Application’為‘prism:PrismApplication’且刪除StartupUri xmal程式碼如下:
<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}";
2.自定義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>());