天天看點

【.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

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

2、建立完成以後,如下圖所示。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

3、再建立一個WPF類庫項目,用于存放所有第三方nuget包。此處純個人習慣,用于防止多項目引用包的時候,産生包版本不一緻的問題。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

4、包項目裡面,添加三個核心的包。分别是:Prism.Unity 、   Prism.Unity.Extensions   和  Unity.Microsoft.DependencyInjection  

其中,Prism.Unity 、   Prism.Unity.Extensions  用于提供基礎的Prism架構有關的環境以及Unity容器。Unity.Microsoft.DependencyInjection  用于提供可支援屬性注入的方式,如果不使用屬性注入,也可以不使用。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

5、WpfDemo項目裡面,引用剛剛的包項目後,修改App.xaml檔案裡面的預設配置項。以下是預設的内容:

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

6、替換為以下的内容。以下内容代表的是該程式引入prism架構。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

7、App.cs類裡面,繼承改為PrismApplication,并且提供幾個方法的重寫。如果沒有重寫,可能會提示錯誤。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

8、都載入以後,運作程式,就可以啟動畫面了。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

9、項目建立Views檔案夾和ViewModels檔案夾。prism架構預設會自動識别存在Views檔案夾的為視圖端,ViewModels檔案夾為VM端,用于自動雙向綁定的比對使用。

并且VM類與Views視圖必須名稱對應,VM類的結尾必須是xxxViewModel。

先建立一個登入頁面,存放于Views檔案夾下,然後頁面引入prism架構所需的目錄,如圖所示。

同時設定了一個頁面名稱,該名稱後面當做參數進行傳遞使用。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

10、建立對應Login窗體的VM類 LoginViewModel,并且繼承BindbleBase類,用于提供prism的雙向綁定功能。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

11、提供使用者名、密碼屬性,以及用于按鈕觸發的事件屬性。并且提供了一個模拟使用者登入的方法。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

12、在Login.xaml檔案下,新增兩個輸入框和一個按鈕,用于模拟使用者登入功能和雙向綁定功能。Mode=TwoWay的意思是,前端資料變更,會自動同步到後端綁定的屬性上;後端綁定的屬性如果被修改值了,也會傳遞到前端進行同步顯示。還有其他的Mode,小夥伴們可以自行去嘗試。

Command指令用于綁定事件屬性,并且提供了一個參數,把目前頁面當做參數傳入進去,用于頁面跳轉使用;如果不需要參數的情況下,直接不需要CommandParameter屬性就行。Command指令預設是滑鼠單擊事件,如果是其他事件需要實作,可以自定義做一些對應的事件的封裝來進行實作。

其他說明:任意屬性都是可以通過雙向綁定進行實作的,包括控件名稱、以下label控件的content屬性、其他屬性等等一系列。大佬們可以自行玩玩,此處提供簡單案例,是以隻對輸入框的Text屬性和按鈕的點選事件提供了雙向綁定的功能。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

13、在App.cs類裡面,提供InitializeShell方法的重寫,并且注冊Login頁面。此處可以實作啟動時候打開登入頁面,通過提供DialogResult屬性以後,就可以打開CreateShell方法裡面注冊的頁面了。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

14、現在運作程式,打開了登入頁面,進行驗證一下,如下圖所示,說明驗證生效了。輸入正确的使用者名和密碼就可以進入到MainWindow頁面。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

15、接下來試試依賴注入的使用。先建立一個WPF類庫項目,提供一個LoginService類與接口當做服務;并提供UserLogin方法的實作,如下圖所示。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

16、項目引用以後,提供屬性注入。屬性注入需要使用public,并且是屬性,以及添加 Dependency的标記;如果是構造函數注入,則無需這些步驟。然後在登入方法裡面,提供注入方法的使用,如下圖所示。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

17、在App.cs類裡面,先前提供的重寫方法 RegisterTypes方法裡面,進行服務的注冊。

以下提供了一個瞬時生命周期的注入,如下所示。如果要使用其他生命周期,大佬們可以自行研究,都是自帶的,我就不多寫了。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

18、最後,運作程式,檢視效果,程式運作符合預期,說明使用unity ioc容器進行服務注冊成功。

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

19、 後記——有關代碼奉上:

App.xaml 

<prism:PrismApplication x:Class="WpfDemo.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfDemo"
             xmlns:prism="http://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="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:WpfDemo.Views"
        xmlns:prism="http://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;
            }
        }

    }      

以上就是本篇文章的全部内容,歡迎大佬們點贊、評論或轉發。如需轉發,記得注明出處喲~ 謝謝大家圍觀。

歡迎加入QQ群:

群号:1079830632

【.NET6+WPF】WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入

繼續閱讀