WPF: WpfWindowToolkit 一個視窗操作庫的介紹

来源:https://www.cnblogs.com/wpinfo/archive/2018/01/20/WpfWindowToolkit_Intro.html
-Advertisement-
Play Games

在 XAML 應用的開發過程中,使用 MVVM 框架能夠極大地提高軟體的可測試性、可維護性。MVVM 的核心思想是關註點分離,使得業務邏輯從 View 中分離出來到 ViewModel 以及 Model 中,從邏輯上來講,這也是業務邏輯應該處的位置。 具體來說,藉助於數據綁定 (Data Bindi ...


XAML 應用的開發過程中,使用 MVVM 框架能夠極大地提高軟體的可測試性、可維護性。MVVM 的核心思想是關註點分離,使得業務邏輯從 View 中分離出來到 ViewModel 以及 Model 中,從邏輯上來講,這也是業務邏輯應該處的位置。 

具體來說,藉助於數據綁定 (Data Binding) 以及命令 (Command) 等這些XAML 平臺自身所提供的機制,使得 MVVM 在 XAML 平臺上很容易實現。但是,如果你對 XAML 應用開發以及 MVVM 的使用有一定的經驗,你會發現,單純 MVVM 本身並不能解決所有問題,比如頁面導航、彈出對話框、視窗操作等,這時就需要結合一些與它相關的技術,如消息、行為、服務以及依賴註入等。這個原因是 MVVM 主要針對的是 View 的內容,而不是 View 本身的操作或其它別的東西,所以像彈出視窗或者頁面導航之類的操作就需要上述技術的配合。 

更具體一點,在 WPF 應用的開發過程中,很多時候我們需要打開和關閉視窗。要以“MVVM方式”來實現,就不容易。當然,我們可以使用消息來解決這個問題。不過,如果過多地使用消息,也會使代碼難以維護並且增加調試的難度。 

本文主要通過分享一個類庫來解決這一問題:WpfWindowToolkit,就如名稱所示,它是針對視窗的一些操作類的集合

一、基本介紹

從介紹里,我們可以看出,它可以解決視窗的打開與關閉,以及在視窗間傳遞參數和返回值等類的問題,而實現這一切都不需要我們在 View 的 CodeBehind 中寫任何代碼,也不需要藉助於消息,所需要作的修改僅在 XAML 代碼和 ViewModel 中,從而遵循了 MVVM 的原則並達到了其目的。 

Github (http://github.com/imnbwd/WpfWindowToolkit)下載到源碼後,其中有 Demo,通過這個 Demo 我們可以瞭解它是如何使用的。在以下的內容里,我們先簡單對它有些瞭解,更為具體的內容則可以看它的源碼和 Demo。

二、安裝

要在項目中使用它,可以從 Nuget 上下載,或者直接使用命令:

InstallPackage WpfWindowToolkit

三、如何使用

1. 打開視窗

有兩種方式:使用附加屬性或行為。

在使用時,需要先添加命名空間:

    xmlns:behaviors="clr-namespace:PraiseHim.Rejoice.WpfWindowToolkit.Behaviors;assembly=WpfWindowToolkit"
    xmlns:helpers="clr-namespace:PraiseHim.Rejoice.WpfWindowToolkit.Helpers;assembly=WpfWindowToolk

附加屬性:

    <Button x:Name="btn1"
        helpers:WindowHelper.OpenWindowType="{x:Type local:Window1}"
        Content="Open window using Window Helper" />

行為:

    <Button x:Name="btn5"
        Margin="0,5,0,0"
        Content="Open window with parameter using action">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                 <behaviors:OpenWindowAction Parameter="WPF (action)" WindowType="{x:Type local:Window1}" /> 
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>

可以看出,它們都是通過將要打開的視窗的類型(Type) 指定給 WindowType 屬性。

2. 打開視窗時傳遞參數

要在打開視窗的同時,向其 ViewModel 傳遞參數,也很簡單。同上面一樣,只需要再為 Parameter 屬性賦值即可,這個 Parameter 可以綁定到當前視窗的 ViewModel 的成員上,因此,可以將任何類型的數據傳遞給要打開的視窗。

接下來,則是需要註意的,要對被打開的視窗的 ViewModel 作一些修改:使它繼承 ViewModelBaseData<T>,這裡的 T 就是所傳遞參數的類型。然後,通過 InternalData 屬性即可得到傳遞過來的參數。 

    <behaviors:OpenWindowAction Parameter="WPF (action)" WindowType="{x:Type local:Window1}" />
    public class Window1ViewModel : ViewModelBaseData<string>
    {   
        protected override string InternalData { get; set; }
        ...
    }

在打開視窗時,還有一種複雜的方式,同時也會給使用者更靈活的控制。方法是,當前視窗繼承 ViewModelBaseEx 類,然後調用它的 ShowWindow 方法。在此,再不詳述,具體可以參考 Github 上的說明文檔。

3. 從被打開的視窗中返回值

當關閉打開的視窗,要實現這個目的,也需要兩步,首先,第一個視窗(要打開其它視窗的那個視窗)的 ViewModel 需要繼承 ViewModelBaseEx,或 ViewModelBaseEx<T> 類,然後使用 ShowWindow(OpenWindowInfo, Action<TReturnValue>) 方法來打開視窗,其中第二個參數是一個帶參數的 Action,這裡的參數就是返回值,在這個 Action 中,我們就可以處理返回值 。

    public class ReturnValueMainWindowViewModel : ViewModelBaseEx<Friend>
    {
        public void ShowFriendSelectionWindow()
        {
            this.ShowWindow(new OpenWindowInfo { WindowType = typeof(ReturnValueTestWindow) }, friend =>
            {
                if (friend != null)
                {
                    MessageBox.Show($"You have selected this friend: {friend.Name}");
                }
                else
                {
                    MessageBox.Show("No friend has been selected");
                }
            });
        }
    }

第二步,被打開的視窗的 ViewModel,需要實現 IWindowReturnValue<T> 介面,這個介面包含 ReturnValue 屬性,我們只要為它賦值就可以了。 

    public class ReturnValueTestWindowViewModel : BindableBase, IWindowReturnValue<Friend>
    {
        ...
        public void SetReturnValue() 
        {
            ReturnValue = SelectedFriend;
        }
        ...
    }

4. 關閉視窗

在 View 中關閉

要關閉視窗,可以使用 CloseWindowAction,如下:

    <Button Content="Close the current window with confirmation">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Click">
                <behaviors:CloseWindowAction ClosingCheckFunc="{Binding CheckBeforeCloseWindow}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>

它提供一個屬性 ClosingCheckFunc,可以綁定到一個返回布爾值的函數,如果此函數返回 true,則關閉,否則,則不關閉。

 處理 Window.Closing 事件

除此以外,在視窗被關閉時,它也提供對 Window 的 Closing 事件的支持,通常我們可能會在這個事件處理中來詢問是否關閉視窗。要這麼做,只要為當前視窗添加一個行為即可,如下: 

    <i:Interaction.Behaviors>
        <behaviors:ClosingWindowBehavior ClosingCheckFunc="{Binding CheckBeforeCloseWindow}" />
    </i:Interaction.Behaviors>

而其中的 ClosingCheckFunc 屬性所指向的方法則是我們在 ViewModel 中添加的判斷邏輯。

在 ViewModel 中關閉視窗

此外,它也支持在 ViewModel 的中來關閉當前視窗,首先,為視窗添加行為: 

    <Window>
        <i:Interaction.Behaviors>
            <behavior:EnableWindowCloseBehavior />
        </i:Interaction.Behaviors>
    ...
    </Window>

然後,ViewModel 需要實現 IClosable 介面,它包含一個 Action,名為CloseAction 併在合適的位置調用 CloseAction 即可。 

    public class CloseTestViewModel : BindableBase, IClosable
    {
        public Action CloseWindow { get; set; }
        ...
    }
   CloseWindow?.Invoke();  // or just CloseWindow();

 總結

本文主要介紹了 WPF 視窗操作庫——WpfWindowToolkit 的使用,它完全支持 MVVM,能夠解決視窗的打開、關閉、視窗間的傳值與返回值等問題。如果你正在開發 WPF 應用,並且採用了 MVVM 模式,不妨試一個這個庫。要想多瞭解,可以到 Github 上下載其源碼。

如果什麼問題或建議,歡迎隨時交流。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 上面只是做到讀取並寫入另一個文件,並沒有進行排序 下麵是排序的方法 ...
  • 題目描述 某人寫了n封信和n個信封,如果所有的信都裝錯了信封。求所有信都裝錯信封共有多少種不同情況。 輸入輸出格式 輸入格式: 一個信封數n(n<=20) 輸出格式: 一個整數,代表有多少種情況。 輸入輸出樣例 輸入樣例#1: 複製 2 輸出樣例#1: 複製 1 輸入樣例#1: 複製 2 輸出樣例# ...
  • Tomcat 是什麼 Tomcat 是由 Apache 開發的一個 Servlet 容器,實現了對 Servlet 和 JSP 的支持,並提供了作為Web伺服器的一些特有功能,如Tomcat管理和控制平臺、安全域管理和Tomcat閥等。 由於 Tomcat 本身也內含了一個 HTTP 伺服器,它也可 ...
  • 題目描述 HXY得到了一些卡片,這些卡片上標有數字0或5。現在她可以選擇其中一些卡片排成一列,使得排出的一列數字組成的數最大,且滿足被90整除這個條件。同時這個數不能含有前導0,即0不能作為這串數的首位。如果不能排出這樣的數,輸出“-1”。 輸入輸出格式 輸入格式: 第一行,卡片的個數n。 第二行, ...
  • 在當前的Java記憶體模型下,線程可以把變數保存在本地記憶體(比如機器的寄存器)中,而不是直接在主存中進行讀寫。這就可能造成一個線程在主存中修改了一個變數的值,而另外一個線程還繼續使用它在寄存器中的變數值的拷貝,造成數據的不一致。 在當前的Java記憶體模型下,線程可以把變數保存在本地記憶體(比如機器的寄存 ...
  • package com.swift; public class Bank_Customer_Test { public static void main(String[] args) { /* * 兩個客戶往一個銀行存錢,每人存三十次一次存一百。 模擬銀行存錢功能,時時銀行現金數。 */ Custo... ...
  • 【01】淺談Google Chrome瀏覽器(理論篇) 【02】淺談Google Chrome瀏覽器(操作篇)(上) 【03】淺談Google Chrome瀏覽器(操作篇)(下) 【04】淺談ASP.NET框架 【05】淺談ASP.NET MVC運行過程 【06】淺談ASP.NET MVC 控制器 ...
  • 在使用Entity Framework時,若有多個排序,需要OrderBy (OrderByDescending)再ThenBy (ThenByDescending) 假設需要根據Name升序排序,再根據Id降序排序,則: 藉助System.Linq.Dynamic的方式 首先需要在項目中引用Sys ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...