通常,為用戶界面應用影片只不過是創建并配置正確的影片和故事板物件,但在其他情況下,特別是同時發生多個影片時,可能需要更加關注性能,特定的效果更可能導致這些問題——例如,那些涉及視頻、大位圖以及多層透明等的效果通常需要占用更多CPU開銷,如果不謹慎實作這類效果,運行它們使可能造成明顯抖動,或者會從其他同時運行的應用程式搶占CPU時間,
幸運的是,WPF提供了幾個可提供幫助的技巧,接下來的幾節將學習降低最大幀率以及快取計算機顯卡中的位圖,這兩種技術可以減輕CPU的負擔,
一、期望的幀率
正如前面所學習的,WPF試圖保持以60幀/秒的速度運動影片,這樣可確保從開始到結束得到平滑流暢的影片,當然,WPF可能達不到這個目標,如果同時運行多個復雜的影片,并且CPU或顯卡不能承受的話,整個幀率可能會下降(最好的情形),甚至可能會跳躍以進行補償(最壞的情形),
盡管很少提高幀率,但可能會選擇降低幀率,這可能是因為以下兩個原因之一:
- 影片使用更低的幀率看起來也很好,所以不希望浪費額外的CPU周期,
- 應用程式運行在性能較差的CPU或顯卡上,并知道使用高的幀率時整個影片的渲染效果還不如使用更低的幀率的渲染效果好,
調整幀率很容易,只需要為包含影片的故事板使用Timeline.DesiredFrameRate附加屬性,下面的示例將幀率減半:
<Storyboard Timeline.DesiredFrameRate="30">
下圖顯示了一個簡單的測驗程式,該程式為一個小球應用影片,使其在Canvas控制元件上沿一條曲線運動,

這個應用程式開始在Canvas上繪制Ellipse物件,Canvas.ClipToBounds屬性被設定為true,所以圓的邊緣不會超出Canvas控制元件的邊緣而進入視窗的其他部分,
<Canvas ClipToBounds="True"> <Ellipse Name="ellipse" Fill="Red" Width="10" Height="10"></Ellipse> </Canvas>
為在Canvas控制元件上移動圓,需要同時進行兩個影片——一個影片用于更新Canva.Left屬性(從左向右移動圓),另一個影片用于改變Canvas.Top屬性(使圓上升,然后下降),Canvas.Top影片是可反轉的——一旦圓達到最高點,就會下降,Canvas.Left影片不是可反轉的,但持續時間是Canvas.Top影片的兩倍,從而使得這兩個影片可以同時移動圓,最后的技巧是為Canvas.Top影片使用DeceleartionRatio屬性,這樣,當圓達到最高點是上升的速度會更慢,這會創建更逼真的效果,
下面是影片的完整標記:
<Window.Resources> <BeginStoryboard x:Key="beginStoryboard"> <Storyboard Timeline.DesiredFrameRate="{Binding ElementName=txtFrameRate,Path=Text}"> <DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Left)" From="0" To="300" Duration="0:0:5"> </DoubleAnimation> <DoubleAnimation Storyboard.TargetName="ellipse" Storyboard.TargetProperty="(Canvas.Top)" From="300" To="0" AutoReverse="True" Duration="0:0:2.5" DecelerationRatio="1"> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Window.Resources>
這個示例的真正目的是嘗試不同的幀率,為查看某個特定幀率的效果,只需要在文本框中輸入合適的數值,然后單擊Repeat按鈕即可,然后影片就會使用新的幀率(通過資料系結運算式獲取新的幀率)觸發,從而可以觀察影片的效果,在更低的幀率下,橢圓不會均勻移動——而會在Cavans控制元件中的跳躍,
也可使用代碼調整Timeline.DesiredFrame屬性,例如,可能希望讀取靜態屬性RenderCapability.Tier以確定顯卡支持的渲染級別,
二、位圖快取
位圖快取通知WPF獲取內容的當前位圖影像,并將其復制到顯卡的記憶體中,這時,顯卡可以控制位圖的操作和顯示的重繪,這個處理程序比讓WPF完成所有作業要快很多,并且和顯卡不斷通信,
如果運用得當,位圖快取可以改善應用程式的繪圖性能,但如果運用不當,就會浪費顯存并且實際上會降低性能,所以,在使用位圖快取之前,需要確保真正合適,下面列出一些指導原則:
- 如果正在繪制的內容需要頻繁地重新繪制,使用位圖快取可能是合理的,因為每次后續的重新繪制將更快,一個例子是當其他一些具有影片的物件浮動在形狀表面上時,使用BitmapCacheBrush畫刷繪制形狀的表面,盡管形狀沒有變化,但是形狀的不同部分被遮擋住或顯露出來,從而需要重新繪制,
- 如果元素的內容經常變化,使用位圖快取可能不合理,因為可視化內容每次改變時,WPF需要重新渲染位圖將其發送到顯卡快取,而這需要耗費時間,該規則有些晦澀,因為某些改變不會導致快取無效,安全操作的例子包括使用變換旋轉以及重新縮放元素、剪裁元素、改變元素的透明度以及應用效果,另一方面,改變元素的內容、布局以及各式將強制重新渲染位圖,
- 盡量少快取內容,位圖越大,WPF存盤快取副本所需的時間越長,需要的顯存越多,一旦耗盡顯存,WPF將被迫使用更慢的軟體渲染,
為更好地理解位圖快取,使用一個簡單示例是有幫助的,下圖例舉一個示例,一個影片推動一個簡單的影像——正方形——在Canvas面板上移動,Canvas面板包含一條具有復雜集合圖形的路徑,但正方形在Canvas面板表面上移動時,強制WPF重新計算路徑并填充丟失的部分,這會帶來極大的CPU負擔,并且影片甚至可能開始變得斷斷續續,

可采用幾種方法解決該問題,一種選擇是使用一幅位圖替換背景,WPF能夠更高效地管理位圖,更靈活的選擇是使用位圖快取,這種方法可繼續將存活的、可互動的元素作為背景,
為啟用位圖快取功能,將相應元素的CacheMode屬性設定為BitmapCache,每個元素都提供了CacheMode屬性,這意味著可以精確選擇為哪個元素使用這一特征,
<Path CacheMode="BitmapCache" ...></Path>
通過這個簡單修改,可立即看到區別,首先,視窗顯示的事件要稍長一些,但影片的運行將更平滑,并且CPU的負擔將顯著降低,可通過Windows任務管理器進行檢查——經常可以看到CPU的負擔從接近100%減少到20%一下,
通常,當啟用位圖快取時,WPF采用元素當前尺寸的快照并將其位圖復制到顯卡中,如果之后使用ScaleTransform放大元素,這會變成一個問題,在這種情況下,將放大快取的位圖,而不是實際的元素,當放大元素時這會導致模糊放大以及色塊,
例如,設想一個修訂過的示例,在這個示例中,第二個同步影片擴展Path使其為原始尺寸的10倍,然后碩訓原始尺寸,為確保具有良好的顯示質量,可使用5倍于Path原始尺寸的尺寸快取其位圖:
<Path ...> <Path.CacheMode> <BitmapCache RenderAtScale="5"></BitmapCache> </Path.CacheMode> </Path>
這樣可解決像素化問題,雖然快取的位圖仍比Path的最大影片尺寸(最大尺寸達10倍于其原始尺寸)小,但顯卡能使位圖的尺寸加倍,從5倍到10倍,而不會有任何明顯的縮放問題,更重要的是,這可使應用避免過多地使用顯存,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/2973.html
標籤:WPF
