【.NET6+WPF】WPF使用prism框架+Unity IOC容器實現MVVM雙向綁定和依賴注入
前言:在C/S架構上,WPF無疑已經是「桌面一霸」了。在.NET生態環境中,很多小夥伴還在使用Winform開發C/S架構的桌面應用。但是WPF也有很多年的歷史了,並且基於MVVM的開發模式,受到了很多開發者的喜愛。
並且隨著工業化的進展,以及幾年前微軟對.NET平台的開源,中國大多數企業的工業系統或上位機系統,也慢慢從使用MFC、QT等C++平台,轉向了.NET平台。並且.NET平台上,桌面應用上,WPF由於其獨特的一些特性、以及可以製作動畫、無損影像等,WPF的佔比也越來越高。但是大多數小夥伴可能還是按照開發Winform的傳統思路來開發WPF,所以這篇文章當做是一個使用MVVM模式開發的入門教程,希望大家在開發WPF的過程中,可以享受MVVM雙向綁定的快樂。
本篇文章有關環境說明:
開發環境: VS 2022企業版
.NET版本環境:.NET 6
開發的作業系統環境:Win 10
1、先創建一個WPF應用程式,環境選擇.NET 6
2、創建完成以後,如下圖所示。
3、再新建一個WPF類庫項目,用於存放所有第三方nuget包。此處純個人習慣,用於防止多項目引用包的時候,產生包版本不一致的問題。
4、包項目裡面,添加三個核心的包。分別是:Prism.Unity 、 Prism.Unity.Extensions 和 Unity.Microsoft.DependencyInjection
其中,Prism.Unity 、 Prism.Unity.Extensions 用於提供基礎的Prism框架有關的環境以及Unity容器。Unity.Microsoft.DependencyInjection 用於提供可支援屬性注入的方式,如果不使用屬性注入,也可以不使用。
5、WpfDemo項目裡面,引用剛剛的包項目後,修改App.xaml文件裡面的默認配置項。以下是默認的內容:
6、替換為以下的內容。以下內容代表的是該程式引入prism框架。
7、App.cs類裡面,繼承改為PrismApplication,並且提供幾個方法的重寫。如果沒有重寫,可能會提示錯誤。
8、都載入以後,運行程式,就可以啟動畫面了。
9、項目新建Views文件夾和ViewModels文件夾。prism框架默認會自動識別存在Views文件夾的為視圖端,ViewModels文件夾為VM端,用於自動雙向綁定的匹配使用。
並且VM類與Views視圖必須名稱對應,VM類的結尾必須是xxxViewModel。
先建立一個登錄頁面,存放於Views文件夾下,然後頁面引入prism框架所需的目錄,如圖所示。
同時設置了一個頁面名稱,該名稱後面當做參數進行傳遞使用。
10、新建對應Login窗體的VM類 LoginViewModel,並且繼承BindbleBase類,用於提供prism的雙向綁定功能。
11、提供用戶名、密碼屬性,以及用於按鈕觸發的事件屬性。並且提供了一個模擬用戶登錄的方法。
12、在Login.xaml文件下,新增兩個輸入框和一個按鈕,用於模擬用戶登錄功能和雙向綁定功能。Mode=TwoWay的意思是,前端數據變更,會自動同步到後端綁定的屬性上;後端綁定的屬性如果被修改值了,也會傳遞到前端進行同步顯示。還有其他的Mode,小夥伴們可以自行去嘗試。
Command命令用於綁定事件屬性,並且提供了一個參數,把當前頁面當做參數傳入進去,用於頁面跳轉使用;如果不需要參數的情況下,直接不需要CommandParameter屬性就行。Command命令默認是滑鼠單擊事件,如果是其他事件需要實現,可以自定義做一些對應的事件的封裝來進行實現。
其他說明:任意屬性都是可以通過雙向綁定進行實現的,包括控制項名稱、以下label控制項的content屬性、其他屬性等等一系列。大佬們可以自行玩玩,此處提供簡單案例,所以只對輸入框的Text屬性和按鈕的點擊事件提供了雙向綁定的功能。
13、在App.cs類裡面,提供InitializeShell方法的重寫,並且註冊Login頁面。此處可以實現啟動時候打開登錄頁面,通過提供DialogResult屬性以後,就可以打開CreateShell方法裡面註冊的頁面了。
14、現在運行程式,打開了登錄頁面,進行驗證一下,如下圖所示,說明驗證生效了。輸入正確的用戶名和密碼就可以進入到MainWindow頁面。
15、接下來試試依賴注入的使用。先創建一個WPF類庫項目,提供一個LoginService類與介面當做服務;並提供UserLogin方法的實現,如下圖所示。
16、項目引用以後,提供屬性注入。屬性注入需要使用public,並且是屬性,以及添加 Dependency的標記;如果是構造函數注入,則無需這些步驟。然後在登錄方法裡面,提供注入方法的使用,如下圖所示。
17、在App.cs類裡面,先前提供的重寫方法 RegisterTypes方法裡面,進行服務的註冊。
以下提供了一個瞬時生命周期的注入,如下所示。如果要使用其他生命周期,大佬們可以自行研究,都是自帶的,我就不多寫了。
18、最後,運行程式,查看效果,程式運行符合預期,說明使用unity ioc容器進行服務註冊成功。
19、 後記——有關程式碼奉上:
App.xaml
<prism:PrismApplication x:Class="WpfDemo.App" xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="//schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfDemo" xmlns:prism="//prismlibrary.com/"> <Application.Resources> </Application.Resources> </prism:PrismApplication>
App.cs
public partial class App : PrismApplication // Application { public App() { } protected override Window CreateShell() { return Container.Resolve<MainWindow>(); } protected override void InitializeShell(Window shell) { if (Container.Resolve<Login>().ShowDialog() == false) { Application.Current?.Shutdown(); } else { base.InitializeShell(shell); } } protected override void RegisterTypes(IContainerRegistry containerRegistry) { containerRegistry.Register<ILoginService, LoginService>(); // 默認是transient註冊 } protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog) { }
LoginViewModel.cs
public class LoginViewModel: BindableBase { [Dependency] // using Unity; public ILoginService _loginService { get; set; } private string userName=""; private string password=""; public string UserName { get { return userName; } set { SetProperty(ref userName, value); } } public string Password { get { return password; } set { SetProperty(ref password, value); } } ICommand? loginCommand; public ICommand LoginCommand { get { if (loginCommand == null) { loginCommand = new DelegateCommand<object>(UserLogin); } return loginCommand; } } void UserLogin(object obj) { if(!_loginService.UserLogin(this.UserName,this.Password)) { MessageBox.Show("用戶名或密碼錯誤"); return; } (obj as Window).DialogResult = true; } }
Login.xaml
<Window x:Class="WpfDemo.Views.Login" xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="//schemas.microsoft.com/winfx/2006/xaml" xmlns:d="//schemas.microsoft.com/expression/blend/2008" xmlns:mc="//schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfDemo.Views" xmlns:prism="//prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" mc:Ignorable="d" Name="loginWindow" Title="Login" Height="400" Width="600"> <Grid> <Label Content="用戶名" HorizontalAlignment="Left" Margin="56,119,0,0" VerticalAlignment="Top"/> <Label Content="密碼" HorizontalAlignment="Left" Margin="65,150,0,0" VerticalAlignment="Top"/> <TextBox HorizontalAlignment="Left" Margin="112,124,0,0" TextWrapping="Wrap" Text="{Binding UserName,Mode=TwoWay}" VerticalAlignment="Top" Width="143"/> <TextBox HorizontalAlignment="Left" Margin="112,154,0,0" TextWrapping="Wrap" Text="{Binding Password,Mode=TwoWay}" VerticalAlignment="Top" Width="143"/> <Button Content="登錄" HorizontalAlignment="Left" Margin="166,192,0,0" Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=loginWindow}" VerticalAlignment="Top" Height="24" Width="89"/> </Grid> </Window>
LoginService.cs
public class LoginService: ILoginService { public Boolean UserLogin(string userName, string password) { if(userName =="wesky" && password == "123456") { return true; } else { return false; } } }
以上就是本篇文章的全部內容,歡迎大佬們點贊、評論或轉發。如需轉發,記得註明出處喲~ 謝謝大家圍觀。