熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

WPF的圖形呈現

2022-06-13   來源: .NET編程 

  本主題概述 WPF 可視化層本主題重點講述 WPF 模型中呈現支持的 Visual 類的角色

  Visual 對象的角色
Visual 類是每個 FrameworkElement 對象所派生自的基本抽象該類還充當在 WPF 中編寫新控件的入口點在 Win 應用程序模型中該類在許多方面可以被視為窗口句柄 (HWND)

  Visual 對象是一個核心 WPF 對象它的主要角色是提供呈現支持用戶界面控件(如 Button 和 TextBox)派生自 Visual 類並使用該類來保持它們所呈現的數據Visual 對象為下列功能提供支持

  輸出顯示呈現 Visual 對象的持久的序列化繪圖內容

  轉換針對 Visual 對象執行轉換

  剪輯為 Visual 對象提供剪輯區域支持

  命中測試確定 Visual 對象的邊界內是否包含坐標或幾何形狀

  邊界框計算確定 Visual 對象的邊框

  但是Visual 對象不包括對非呈現功能的支持
◆事件處理

  ◆布局

  ◆樣式

  ◆數據綁定

  ◆全球化

  Visual 作為子類必須派生自的公共抽象類進行公開下圖顯示了 WPF 中所公開的可視化對象的層次結構

  Visual 類的層次結構

   

  DrawingVisual 類
DrawingVisual 是一個用於呈現形狀圖像或文本的輕量繪圖類此類之所以被視為輕量是因為它不提供布局或事件處理功能從而能夠改善運行時性能因此繪圖最適於背景和剪貼畫DrawingVisual 可用於創建自定義可視化對象

  ViewportDVisual 類
ViewportDVisual 在二維 Visual 和 VisualD 對象之間起到橋梁作用VisualD 類是所有三維可視化元素的基類ViewportDVisual 要求您定義一個 Camera 值和一個 Viewport 值可以借助照相機來查看場景投影映射到二維圖面的區域稱作視區

  ContainerVisual 類
ContainerVisual 類用作 Visual 對象集的容器DrawingVisual 類派生自 ContainerVisual 類這允許它包含可視化對象的集合

  可視化對象中的繪圖內容
Visual 對象將它的呈現數據另存為向量圖形指令列表指令列表中的每一項都以序列化格式表示一組低級別的圖形數據及其相關資源共有四種不同類型的呈現數據可以包含繪圖內容

   

  通過 DrawingContext您可用可視化內容填充 Visual當您使用 DrawingContext 對象的繪圖命令時實際上是存儲一組日後將由圖形系統使用的呈現數據而不是實時繪制到屏幕上

  當您創建 WPF 控件(如 Button)時該控件會為繪圖對象本身隱式生成呈現數據例如設置 Button 的 Content 屬性會導致該控件存儲標志符號的呈現表示

  Visual 將其內容描述為一個或多個包含在 DrawingGroup 中的 Drawing 對象DrawingGroup 還描述不透明蒙板轉換位圖效果和應用於其內容的其他操作呈現內容時DrawingGroup 操作按如下順序應用OpacityMaskOpacityBitmapEffectClipGeometryGuidelineSet 和 Transform

  下圖顯示了在呈現過程中 DrawingGroup 操作的應用順序

   

  DrawingGroup 操作的順序

  在可視化層繪制內容
絕不能直接實例化 DrawingContext但可以通過某些方法

  (例如 DrawingGroup::Open 和 DrawingVisual::RenderOpen)獲取繪圖上下文下面的示例從 DrawingVisual 中檢索 DrawingContext 並將其用於繪制矩形

   

  在可視化層枚舉繪圖內容
此外Drawing 對象還可提供用來枚舉 Visual 內容的對象模型

  說明
您在枚舉可視化層的內容時就是相當於在檢索 Drawing 對象而不是以向量圖形指令列表形式檢索呈現數據的基礎表示

下面的示例使用 GetDrawing 方法來檢索 Visual 的 DrawingGroup 值並枚舉該值

   

  如何使用可視化對象來生成控件
WPF 中的許多對象都由其他可視化對象組成這意味著它們可以包含子代對象的各種層次結構WPF 中的許多用戶界面元素(如控件)都由多個表示不同類型呈現元素的可視化對象組成例如Button 控件可以包含許多其他對象其中包括 ClassicBorderDecoratorContentPresenter 和 TextBlock

  下面的代碼顯示的是在標記中定義的 Button 控件

   

  如果您要枚舉包含默認 Button 控件的可視化對象則將發現如下所示的可視化對象層次結構

  可視化樹層次結構的關系圖

   

  Button 控件包含一個 ClassicBorderDecorator 元素該元素又包含一個 ContentPresenter 元素ClassicBorderDecorator 元素負責為 Button 繪制邊框和背景ContentPresenter 元素負責顯示 Button 的內容在本例中由於您要顯示文本因此 ContentPresenter 元素中包含一個 TextBlock 元素Button 控件使用 ContentPresenter這意味著該控件的內容可以由其他元素(如 Image)或幾何形狀(如 EllipseGeometry)來表示

  控件模板
將控件擴展為控件層次結構的關鍵在於 ControlTemplate控件模板為控件指定默認的可視化層次結構當您顯式引用某個控件時會隱式引用它的可視化層次結構您可以重寫控件模板的默認值以便為控件創建自定義的可視化外觀例如您可以修改 Button 控件的背景顏色值以便它使用線性漸變顏色值而不使用純色值

  用戶界面元素(如 Button 控件)包含幾個向量圖形指令列表這些列表描述控件的全部呈現定義下面的代碼顯示的是在標記中定義的 Button 控件

   

  如果您要枚舉包含 Button 控件的可視化對象和向量圖形指令列表

  則將發現如下所示的可視化對象層次結構

  可視化樹和呈現數據的關系圖

   

  Button 控件包含一個 ClassicBorderDecorator 元素該元素又包含一個 ContentPresenter 元素ClassicBorderDecorator 元素負責繪制所有構成按鈕邊框和背景的離散圖形元素ContentPresenter 元素負責顯示 Button 的內容在本例中由於您要顯示圖像因此 ContentPresenter 元素中包含一個 Image 元素

  對於可視化對象和向量圖形指令列表的層次結構需要注意多個事項

  該層次結構中的排序表示繪圖信息的呈現順序從可視化元素的根按照從左到右從上到下的順序遍歷子元素如果某個元素有可視化子元素則會先遍歷該元素的子元素然後再遍歷該元素的同級

  層次結構中的非葉節點元素(如 ContentPresenter)用於包含子元素它們並不包含指令列表

  如果可視化元素既包含向量圖形指令列表又包含可視化子級則會先呈現父級可視化元素中的指令列表然後再呈現任何可視化子對象中的繪圖

  向量圖形指令列表中的項按照從左到右的順序呈現

  可視化樹
可視化樹中包含某個應用程序的用戶界面所使用的所有可視化元素由於可視化元素中包含持久的繪圖信息因此您可以將可視化樹視為場景圖其中包含將輸出寫入顯示設備所必需的全部呈現信息該樹匯集了由該應用程序在代碼或標記中直接創建的所有可視化元素該可視化樹還包含由元素(如控件和數據對象)的模板擴展功能創建的所有可視化元素

  

  下面的代碼顯示的是在標記中定義的 StackPanel 元素

  如果您要枚舉包含標記示例中 StackPanel 元素的可視化對象將發現如下所示可視化對象的層次結構

  可視化樹層次結構的關系圖

   
 
呈現順序
通過可視化樹可以確定 WPF 可視化對象和繪圖對象的呈現順序將從位於可視化樹中最頂層節點中的可視化元素根開始遍歷然後將按照從左到右的順序遍歷可視化元素根的子級如果某個可視化元素有子級則將先遍歷該可視化元素的子級然後再遍歷其同級這意味著子可視化元素的內容先於該可視化元素本身的內容而呈現

  可視化樹呈現順序的關系圖

   
 
可視化元素根
可視化元素根是可視化樹層次結構中最頂層的元素在大多數應用程序中可視化元素根的基類是 Window 或 NavigationWindow但是如果您在 Win 應用程序中承載可視化對象則可視化元素根將是在 Win 窗口中承載的最頂層的可視化元素

  與邏輯樹的關系
WPF 中的邏輯樹表示應用程序在運行時的元素盡管您不直接操作該樹但是該應用程序視圖對於了解屬性繼承和事件路由非常有用與可視化樹不同邏輯樹可以表示非可視化數據對象(如 ListItem)在許多情況下邏輯樹密切映射到應用程序的標記定義下面的代碼顯示的是在標記中定義的 DockPanel 元素

   

  如果您要枚舉包含標記示例中 DockPanel 元素的邏輯對象則將發現如下所示邏輯對象的層次結構

  邏輯樹的關系圖

   

  可視化樹和邏輯樹與當前的應用程序元素集合同步並反映對元素進行的任何添加刪除或修改但是這些樹表示不同的應用程序視圖與可視化樹不同邏輯樹不展開控件的 ContentPresenter 元素這意味著同一組對象的邏輯樹和可視化樹之間沒有直接的一對一對應關系實際上在將同一個元素用作參數的情況下調用 LogicalTreeHelper 對象的 GetChildren 方法與調用 VisualTreeHelper 對象的 GetChild 方法會生成不同的結果

  使用 XamlPad 查看可視化樹
WPF 工具 (XamlPad) 提供了一個用來查看和浏覽可視化樹的選項該樹與當前所定義的 XAML 內容相對應單擊菜單欄上的顯示可視化樹[Show Visual Tree]按鈕可顯示相應的可視化樹

  下面將說明如何在 XamlPad 的可視化樹資源管理器[Visual Tree Explorer]面板中將 XAML 內容擴展為可視化樹節點

  XamlPad 中的可視化樹資源管理器[Visual Tree Explorer]面板

   

  請注意LabelTextBox 和 Button 控件在 XamlPad 的可視化樹資源管理器[Visual Tree Explorer]面板中各自顯示一個可視化對象層次結構這是由於 WPF 控件具有一個包含其可視化樹的 ControlTemplate當您顯式引用某個控件時會隱式引用它的可視化層次結構

  分析可視化性能
WPF 提供了一套性能分析工具來幫助您分析應用程序的運行時行為並確定可以應用的性能優化的類型可視化探查器工具通過直接映射到應用程序的可視化樹來為性能數據提供一個豐富的圖形視圖在此屏幕快照中可視化探查器的CPU Usage[CPU 使用率]部分使您可以清楚地了解對象對 WPF 服務(如呈現和布局)的使用情況

  可視化探查器顯示輸出

   

  可視化對象的呈現行為
WPF 引進了幾個影響可視化對象呈現行為的功能保留的模式圖形矢量圖形和與設備無關的圖形

  保留的模式圖形
了解即時模式和保留模式圖形系統之間的區別是了解 Visual 對象角色的要點之一基於 GDI 或 GDI+ 的標准 Win 應用程序使用即時模式圖形系統這意味著應用程序負責重新繪制工作區中由於某項操作(如調整窗口大小)或者對象的可視化外觀發生變化而失效的部分

  Win 呈現順序的關系圖

  
與之相比WPF 使用保留模式系統這意味著具有可視化外觀的應用程序對象定義一組序列化繪圖數據在定義了繪圖數據之後系統會響應所有的重新繪制請求來呈現應用程序對象甚至在運行時您也可以修改或創建應用程序對象並仍舊依賴系統響應繪制請求保留模式圖形系統中有一個強大功能那就是繪圖信息總是由應用程序保持為序列化狀態但是呈現功能仍由系統負責下面的關系圖演示應用程序如何依賴 WPF 來響應繪制請求

  WPF 呈現順序的關系圖

  
智能重繪
使用保留模型圖形的最大好處之一就是WPF 可以高效率地優化需要在應用程序中重繪的內容即使您有一個具有各種不透明度的復雜場景通常也不必編寫特殊用途的代碼來優化重繪功能請將智能重繪功能與 Win 編程進行比較在後者中可以通過最小化更新區域中的重繪量來盡力優化應用程序

  向量圖形
WPF 使用向量圖形作為其呈現數據的格式向量圖形(包括可縮放的向量圖形 (SVG)Windows 元文件 (wmf) 和 TrueType 字體)存儲呈現數據並以指令列表的形式傳輸該呈現數據這些指令描述如何使用圖形基元來重新創建圖像例如TrueType 字體是描述一組直線曲線和命令(而不是像素數組)的矢量字矢量圖形的主要好處之一就是能夠伸縮到任何大小和分辨率

  與矢量圖形不同位圖圖形以圖像的逐像素表示形式來存儲呈現數據而且在特定的分辨率下預先呈現位圖圖形格式和矢量圖形格式的主要區別之一就是對原始圖像的保真度例如當某個源圖像的大小發生變化時位圖圖形系統會拉伸該圖像而向量圖形系統會伸縮該圖像從而保持圖像的保真度

  下圖顯示了源圖像在放大到 倍時的情況請注意當源圖像作為位圖圖形拉伸時會發生失真而當源圖像作為矢量圖形伸縮時則不會發生失真

  光柵圖形和矢量圖形之間的區別

  
下面的標記顯示所定義的兩個 Path 元素第二個元素使用 ScaleTransform 將第一個元素的繪圖指令放大到 請注意 Path 元素中的繪圖指令保持不變

   

  關於分辨率和與設備無關的圖形
可通過以下兩個系統因子來確定屏幕上的文本大小和圖形大小分辨率和 DPI分辨率描述出現在屏幕上的像素數量由於分辨率變大因此像素會變小從而導致所顯示的圖形和文本會變小在將顯示器的分辨率從 x 更改為 x 顯示器上所顯示的圖形會小得多

  另一個系統設置 (DPI) 以像素數來描述屏幕英寸的大小大多數 Windows 系統的 DPI 都為 這意味著一屏幕英寸等於 個像素增加 DPI 設置會使屏幕英寸變大減小 DPI 會使屏幕英寸變小這意味著屏幕英寸與實際的英寸不相等在多數系統上二者很有可能不相等當您增加 DPI 時屏幕英寸會變大因此支持 DPI 的圖形和文本也會變大增加 DPI 可能會增強文本的可讀性在高分辨率下尤其如此

  並非所有的應用程序都支持 DPI一些應用程序將硬件像素作為其主要計量單位更改系統 DPI 不會對這些應用程序產生任何影響許多其他應用程序都使用支持 DPI 的單位來描述字號使用像素來描述任何其他內容DPI 太小或太大都可能會導致這些應用程序出現布局問題因為應用程序的文本會隨著系統的 DPI 設置而伸縮而應用程序的 UI 卻不會出現此類問題對於使用 WPF 開發的應用程序此問題已經消除

  WPF 支持通過將與設備無關的像素(而不是硬件像素)用作其主要計量單位來自動伸縮圖像和文本會適當伸縮而無需應用程序開發人員執行任何額外的工作下圖顯示了 WPF 文本和圖形在不同 DPI 設置下的顯示方式的示例

  不同 DPI 設置下的圖形和文本

   

VisualTreeHelper 類
VisualTreeHelper 類是一個靜態幫助器類它提供了一個要在可視化對象級別編程的低級功能該類在非常特殊的方案(如開發高性能自定義控件)中非常有用

  在大多數情況下更高級的 WPF 框架對象(如 Canvas 和 TextBlock)提供更大的靈活性且更易於使用

  命中測試
VisualTreeHelper 類提供了當默認的命中測試支持無法滿足您的需要時針對可視化對象的命中測試方法可以在 VisualTreeHelper 類中使用 HitTest 方法來確定幾何形狀或點坐標值是否位於給定對象(如控件或圖形元素)的邊界內例如您可以使用命中測試來確定鼠標在對象邊框中的單擊點是否落在圓形幾何形狀內部您還可以選擇重寫對命中測試的默認實現來執行自己的自定義命中測試計算

  枚舉可視化樹
VisualTreeHelper 類提供了用來枚舉可視化樹成員的功能若要檢索父級請調用 GetParent 方法若要檢索可視化對象的子級或直接子代請調用 GetChild 方法此方法返回父級在指定索引處的子 Visual

  下面的示例演示如何枚舉一個可視化對象的所有子代如果您對序列化可視化對象層次結構的所有呈現信息感興趣則可能希望使用該技術

   

  在大多數情況下邏輯樹更能表示 WPF 應用程序中的元素盡管您不直接修改邏輯樹但是該應用程序視圖對於了解屬性繼承和事件路由非常有用與可視化樹不同邏輯樹可以表示非可視化數據對象(如 ListItem)
VisualTreeHelper 類提供用來返回可視化對象邊框的方法可以通過調用 GetContentBounds 來返回可視化對象的邊框可以通過調用 GetDescendantBounds 來返回可視化對象及其所有子代的邊框下面的代碼演示如何計算可視化對象及其所有子代的邊框

   


From:http://tw.wingwit.com/Article/program/net/201311/11370.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.