回顧
上一篇我們介紹了WPF基本的知識。並且介紹了WPF與winform傳統的cs案頭應用編程模式上的變化,這篇,我們將會對WPF的一些基礎的知識做一個簡單的介紹,關於這些基礎知識更深入的應用則在後續的篇幅中大幅度的應用。
本文大綱
- 什麼是xaml
- 什麼是路由事件
- WPF都提供了那些基礎控制項
- 什麼是相依性屬性
- 元素繫結
- WPF中的資源
- WPF的幾種布局方式
什麼是Xaml
Xaml(Extensible Application Markup Language) 可擴充應用程式標記語言,該語言基於xml實現的進行了相應的擴充。該語言很容易進行擴充,有點類似B/S編程中的代碼後置,前端是HTML,後台是商務邏輯和相關處理代碼。
還有一點是我們反覆強調的,XAML並不是HTML。儘管XAML在元素的聲明、程式樣式的設定和指定事件處理常式上都和HTML非常類似,但是XAML是基於XML的,它是WPF的外在表現形式。而HTML主是一種標記語言,僅僅是用來為瀏覽器呈現頁面內容。XAML除了用來呈現資訊和請求使用者輸入等基本的功能外,它還包含了一些進階的特性,例如它提供了對動畫和3D眾多方面的支援。
xaml語言,微軟提供了可視化的設計工具blend。基於blend建立的的介面模型及效果,都可以儲存或者轉換為xaml格式的代碼,這樣就可以大大的提高了團隊中的設計人員和開發人員之間的協作,減少了設計人員原型效果,開發人員無法實現,設計人員可以自行設計後,轉換為xaml代碼。
關於xaml更多的內容,可以參考維基百科或百度知道。
相關的簡單說明如下:
對於熟悉XML的同仁,應該沒有什麼難理解的。
什麼是路由事件
我們先來看看MSDN給出的定義:
功能定義:路由事件是一種可以針對元素樹中的多個接聽程式(而不是僅針對引發該事件的對象)調用處理常式的事件。
實現定義:路由事件是一個 CLR 事件,可以由 RoutedEvent 類的執行個體提供支援並由 Windows Presentation Foundation (WPF) 事件系統來處理。
我們來解釋下MSDN給出的定義:
1、傳統方式:
對應的xaml代碼和後台代碼如下:
後台對於的處理如下:
當然採用如下的方式也是可行的。
後台代碼修改為:
2、WPF的路由方式:
路由事件使用以下三個路由策略之一:
-
冒泡:針對事件來源呼叫事件處理常式。路由事件隨後會路由到後續的父元素,直到到達元素樹的根。大多數路由事件都使用冒泡路由策略。冒泡路由事件通常用來報告來自不同控制項或其他 UI 元素的輸入或狀態變化。
-
直接:只有源元素本身才有機會調用處理常式以進行響應。這與 Windows 表單用於事件的“路由”相似。但是,與標準 CLR 事件不同的是,直接路由事件支援類處理(類處理將在下一節中介紹)而且可以由 EventSetter 和 EventTrigger 使用。
-
隧道:最初將在元素樹的根處呼叫事件處理常式。隨後,路由事件將朝著路由事件的源節點元素(即引發路由事件的元素)方向,沿路由線路傳播到後續的子項目。在合成控制項的過程中通常會使用或處理隧道路由事件,這樣,就可以有意地禁止顯示複合組件中的事件,或者將其替換為特定於整個控制項的事件。在 WPF 中提供的輸入事件通常是以隧道/冒泡對實現的。隧道事件有時又稱作 Preview 事件,這是由隧道/冒泡對所使用的命名規範決定的。
在傳統的方式中,我們必須對每個事件來源進行事件處理綁定,如果我們新增加新的對象或者新的事件來源,那麼我們還需要添加新的綁定。而這一切在WPF,都被統一處理和考慮了,下面,我們以冒泡為例來簡單說明。
冒泡的順序
修改後台代碼如下:
關於邏輯樹狀結構與視覺化樹狀結構,我們這裡解釋下:
邏輯樹狀結構:簡單來說,就是我們從介面上來看 介面的可視化基本組成部分,這就構成了視窗的一個邏輯樹狀結構。邏輯樹狀結構始終存在於WPF的UI中,不管UI是用XAML編寫還是用代碼編寫。WPF的每個方面(屬性、事件、資源等等)都是依賴於邏輯樹狀結構的
可視樹:可視樹基本上是邏輯樹狀結構的一種擴充。邏輯樹狀結構的每個結點都被分解為它們的核心視覺組件。邏輯樹狀結構的結點對我們而言基本是一個黑盒。而可視樹不同,它暴露了視覺的實現細節。下面是Visual Tree結構就表示了上面四行XAML代碼的視覺樹結構。
可視樹,將介面組成的所有對象本身的內容進行瞭解析,例如button 按鈕,他的內容,是有contentpresenter和textblock構成。
關於邏輯樹狀結構和可視樹的更多介紹,可參考MSDN的介紹。
我這裡給出簡單的擷取邏輯樹狀結構和可視樹的代碼:
都上WPF本身提供了一些方法。採用遞迴的方式。
我們接著上面的關於查看事件來源的地方:
經過上面我們看到了,預設情況下,WPF的事件是採用冒泡的方式進行事件的傳遞的,那麼我們如何採用其他的二種策略呢?
我們再來看下隧道事件,隧道事件的順序如下:引用MSDN中的解釋圖:
輸入事件的冒泡和隧道
事件的處理順序如下所示:
-
針對根項目處理 PreviewMouseDown(隧道)。
-
針對中間元素 1 處理 PreviewMouseDown(隧道)。
-
針對源元素 2 處理 PreviewMouseDown(隧道)。
-
針對源元素 2 處理 MouseDown(冒泡)。
-
針對中間元素 1 處理 MouseDown(冒泡)。
-
針對根項目處理 MouseDown(冒泡)。
我們來驗證下,我們以此處理所有的preview事件,看看是不是按照上面介紹的方式去處理的。
對應的後台代碼如下:
運行,後查看輸出結果:
與我們預期的一致。關於更多的路由事件,我們後面通過單獨的章節來說明。
WPF基礎控制項
系統預設提供的基礎控制項:
有些由於自己也沒有進行深入的使用,可能就不會介紹太詳細。
關於控制項的基本使用,會在後續進行深入的討論和示範。
什麼是相依性屬性
DependencyProperty(相依性屬性):Windows Presentation Foundation (WPF) 提供了一組服務,這些服務可用於擴充通用語言執行平台 (CLR) 屬性的功能,這些服務通常統稱為 WPF 屬性系統。由 WPF 屬性系統支援的屬性稱為依賴項屬性。
WPF介面控制項中的屬性,都可以稱作是相依性屬性,通過相依性屬性,我們能夠實現viewModel與介面元素屬性之間進行綁定。
相依性屬性與我們平時說的屬性有區別的。
1、傳統的屬性
這沒啥好說的,就是我們針對對象進行了封裝。
假設,我們有一個類,有很多的屬性,而且,又被多個對象繼承,我們知道繼承的特性,那麼肯定會有很多的屬性,本身我們可能基本不適用,那麼該屬性,還是會被建立的時候執行個體化,那麼有沒有什麼辦法,我們減少這樣的開銷呢?WPF針對這樣的情況提出了相依性屬性的概念。
2、相依性屬性:
查看其基本的聲明和定義:在注釋中描述:通過方法設定的屬性,資料繫結,動畫,樣式等。
相依性屬性就是自己自己沒有值,通過Binding從資料來源獲得值,就是依賴在別人身上,擁有相依性屬性的對象稱為依賴對象。
我們來看看WPF控制項的基本繼承鏈
- Object類:在.Net中所有類型的根類型
- DispatcherObject類:WPF 中的大多數對象是從 DispatcherObject 派生的,這提供了用於處理並發和線程的基本構造。WPF 基於發送器實現的訊息系統。
- DependencyObject類:表示一個參與依賴項屬性系統的對象。
- Visual類:為 WPF 中的呈現提供支援,其中包括點擊測試、座標轉換和邊界框計算。
- UIElement 類: WPF 核心級實現的基類,該類建立在 Windows Presentation Foundation (WPF) 元素和基本表示特徵基礎上。
- FrameworkElement 類:為 Windows Presentation Foundation (WPF) 元素提供 WPF 架構級屬性集、事件集和方法集。此類表示附帶的 WPF 架構級實現,它是基於由UIElement定義的 WPF 核心級 API 構建的。
- Control類:表示 使用者介面 (UI) 元素的基類,這些元素使用 ControlTemplate 來定義其外觀。
- ContentControl類:表示包含單項內容的控制項。
- ItemsControl類:表示一個可用於呈現項的集合的控制項。
- Decorator類:提供在單個子項目(如 Border 或 Viewbox)上或周圍應用效果的元素的基類。PPT中滑鼠滑過文字框後,出現邊框
- Image類:表示顯示映像的控制項。
- MediaElement類:表示包含音頻和/或視頻的控制項。自己封裝一個視頻播放器
- Panel類:為所有 Panel 元素提供基類。使用 Panel 元素在 Windows Presentation Foundation (WPF) 應用程式中放置和排列子物件。
- Sharp類:為 Ellipse、Polygon 和 Rectangle 之類的形狀元素提供基類。
關於相依性屬性的聲明和更詳細的內容,我們在後續的單獨的章節中有更詳盡的介紹。
幾種應用相依性屬性的情境:
- 希望可在樣式中設定屬性。
- 希望屬性支援資料繫結。
- 希望可使用動態資源引用設定屬性。
- 希望從元素樹中的父元素自動繼承屬性值。
- 希望屬性可進行動畫處理。
- 希望屬性系統在屬性系統、環境或使用者執行的操作或者讀取並使用樣式更改了屬性以前的值時報告。
- 希望使用已建立的、WPF 進程也使用的中繼資料約定,例如報告更改屬性值時是否要求布局系統重新編寫元素的可視化對象。依賴對象建立時並不包含儲存資料空間。WPF中必須使用依賴對象作為相依性屬性的宿主。
後面的章節,我們會結合具體的案例,來說明如何使用相依性屬性。
元素繫結
有了相依性屬性後,我們就可以實現介面的綁定機制了,就會比較容易處理了,既然實現介面的綁定的話,就需要實現介面:INotifyPropertyChanged 實現了該介面的屬性,就可以通過綁定的方式,將屬性綁定到控制項的屬性上
下面給出一個簡單的綁定的例子
我們來查看下,xaml代碼和背景代碼,我們會發現,我們沒有對文字框設定過任何的值,而是通過綁定來實現的賦值操作.
1、xaml代碼如下:
2、後台代碼中,我們並沒有設定任何的關於Textbox的賦值或者設定值的代碼和操作:
3、我們接著看看TestViewModel的實現和要注意的事項:
注意這裡的綁定屬性,必須是public,並且 事件通知的名稱必須與屬性名稱一致。
BaseViewModel的代碼:
後面關於我們進行MVVM編程時,還會使用這部分的內容。
WPF中的資源
WPF中的資源,包含的內容比較多,樣式,圖片,視頻,動畫等,都可以稱作資源。資源,我們一般可以再一個應用程式範圍內容定義公用資源,也可以在一個頁面內定義資源。
我們平時看到有很多的軟體,有很多的主題,在WPF中就可以通過定義樣式來實現,這點有點類似web上的樣式表。
我們可以再運行期動態修改樣式表,達到修改介面的目標。
下面,我們樣式下,如何使用資源,簡單的介紹資源的幾種使用方式,關於更多的資源的介紹,在後續單獨的章節中介紹。
1、添加樣式檔案
添加樣式內容如下:
將樣式檔案添加到App中
運行查看效果:
如果,我們不想使用預設的樣式應該怎麼辦
我們只要自己設定了屬性值後,他就不會使用樣式表中定義的屬性值:
例如,我們只要設定 寬160,高30,字型大小10 然後再次運行看看效果
同樣,如果我們只需要在當前的頁面,應用當前的樣式,那麼我們就不要再App中加入樣式檔案,二是把代碼移動到當前的頁面中:
上面就是對資源檔的簡單介紹,後續會對樣式的設定和應用等結合具體的例子進行更深入的介紹。
WPF的幾種基本布局
1、Grid的布局
這個就沒啥特別好說的,其實,基本上複雜的布局,都需要用到Grid。
主要就是對行和列進行進行設定和定義。
1、行表格
列表格:
包含行和列的表格
2、StackPanel
垂直方向:
3、DockPanel
4、WarpPanel
本文涉及到的內容比較多,但是講述的內容,都不深入,大家對基本的用法有一定的瞭解即可,後續的章節,將會更深入的介紹,並且結合實際項目中的心得體會進行總結和分享。