細數改善WPF應用程序性能的10大方法
WPF(Windows Presentation Foundation)應用程序在沒有圖形加速設備的機器上運行速度很慢是個公開的秘密,給用戶的感覺是它太吃資源了,WPF程序的性能和硬件確實有很大的關系,越高檔的機器性能越有優勢。
程序性能改善不是一蹴而就的,好的設計可以消除影響性能的問題,例如,在運行時構造對象就會對程序的性能造成影響。雖然WPF通過增強的導航等功能提供了更豐富的用戶界面,但你應該考慮你的用戶是否的確需要富圖形界面,盡管WPF有這樣那樣的問題,但在UI設計,特別是自定義風格和控件模板方面,的確給開發人員提供了不少靈活性。
渲染WPF程序的主要因素是它包含的像素量,WPF使用微軟的DirectX在程序運行的硬件上進行渲染,因此,如果你的機器有獨立顯卡,運行WPF程序會更流暢。除了提高硬件配置外,我們來看看10個提高WPF程序性能的軟方法。
1、降低Bitmapscalingmode,加速圖像渲染
當你的WPF程序中包含有動畫時,你可以使用RenderOptions對象的BitmapScalingMode屬性降低資源消耗,需要將BitMapScalingMode屬性的值設為LowQuality,這樣就會使用加速算法處理圖像,而不是默認的高質量圖像重采樣算法。下面的代碼片段顯示了最基本的實現方法:
RenderOptions.SetBitmapScalingMode(imageObject,BitmapScalingMode.LowQuality);
2、在正確的地方使用正確的元素
我們需要在正確的地方使用正確的元素,當你生成樹時應避免使用UIElements作為子或嵌套控件,最好的例子是FlowDocument,我們經常在FlowDocument中使用TextBlock元素。
<FlowDocument> <Paragraph> <TextBlock>some text</TextBlock> </Paragraph> </FlowDocument>
除了上面這樣寫外,我們還可以象下面這樣重寫XAML內容,Run元素不是UIElement,渲染時系統開銷更小。
<FlowDocument><Paragraph><Run>some text</Run></Paragraph></FlowDocument>
類似的例子是使用Label控件的Content屬性,如果在其生命周期內內容不止更新一次,並且是個字符串,這個數據綁定過程可能會阻礙程序的性能,由於內容是一個字符串,在數據綁定期間它會被丟棄,並重新創建。在這種情況下使用TextBlock將數據綁定到Text屬性更有效。
在可視化樹中出現不必要的元素也會降低WPF程序的速度,你最好結合布局優化默認的控件模板。
3、增加靜態資源的使用
靜態資源是預定義的資源,可以連接到XAML屬性,它類似於編譯時綁定,不會影響性能,另一方面,動態資源涉及到運行時查找和對象的構建,從而會影響到性能。但也需要註意,靜態資源需要在編譯時展示。
靜態資源的引用可以參考下面的方法:
<Button Template="{StaticResource RoundButtonWithThickEdge}" x:Name="button1" Content="Button 1" > </Button>
下面的代碼片段顯示了靜態資源RoundButtonWithThickEdge的定義:
<ControlTemplate x:Key="RoundButtonWithThickEdge" TargetType="{x:Type Button}"> <Grid> <Ellipse Fill="{TemplateBinding Background}" Stroke="{x:Null}" HorizontalAlignment="Stretch" x:Name="ellipse"/> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> <Ellipse Stroke="{x:Null}" Margin="2,3,4,5"> <Ellipse.Fill> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFFBFAFA" Offset="0"/> <GradientStop Color="#1DFFFFFF" Offset="1"/> </LinearGradientBrush> </Ellipse.Fill> </Ellipse> </Grid> </ControlTemplate>
4、當你想顯示大型數據時,使用UI虛擬化的控件
想象一下一個組合框綁定大量行時的樣子,它會讓組合框中項目的展現變得非常慢,這是因為在這種情況下,程序需要計算每個項目的具體顯示位置,使用WPF時,你可以延遲這個行為,這就叫做UI虛擬化,它只會在其可見範圍內生產項目顯示需要的容器。
要實現這種效果,你需要將相應控件的IsVirtualizing屬性設為True,例如,Listbox經常用來綁定大型數據集,它是UI虛擬化的重要候選者,其它適宜UI虛擬化的控件包括Combobox,ListView和TreeView。
5、使用延遲滾動增強用戶體驗
如果你還記得可滾動的DataGrid或ListBox,它們往往會降低整個應用程序的性能,因為在滾動時會強制連續更新,這是默認的行為,在這種情況下,我們可以使用控件的延遲滾動(Deferred Scrolling)屬性增強用戶體驗。你需要做的僅僅是將IsDeferredScrollingEnabled附加屬性設為True。
6、使用字體緩存服務提高啟動時間
WPF應用程序之間可以共享字體數據,它是通過一個叫做PresentationFontCache Service的Windows服務實現的,它會隨Windows自動啟動。
你可以在控制面板的“服務”中找到這個服務(或在“運行”框中輸入Services.msc),確保這個服務已經啟動。
7、使用卸載事件卸載不必要的動畫
動畫肯定會占用一定的資源,如果處置方式不當,將會消耗更多的資源,如果你認為它們無用時,你應該考慮如何處理他們,如果不這樣做,就要等到可愛的垃圾回收器先生來回收資源。
例如,假設要刪除一個StoryBorad,在Unload事件中使用StoryBorad的Remove方法,下面的例子來自MSDN。
<EventTrigger RoutedEvent="Page.Unloaded" > <EventTrigger.Actions> <RemoveStoryboard BeginStoryboardName="myBeginStoryboard" /> </EventTrigger.Actions> </EventTrigger>
8、使用容器回收提高性能
你可以通過回收執行虛擬化的容器來提高性能,下面的代碼片段將ViruatlizationMode設為Recycling,它讓你可以獲得更好的性能。當用戶滾動或抵達另一個項目時,它強制重復使用容器對象。
settingVirtualizingStackPanel.VirtualizationMode="Recycling"
9、預測圖像繪制能力
使用RenderCapability.Tier屬性確定機器是支持硬件加速,還是部分硬件加速,疑惑沒有硬件加速,下面的代碼顯示了你要如何檢查Tier。
int displayTier = (System.Windows.Media.RenderCapability.Tier > 16) if (displayTier == 0) { //no hardware acceleration } else if (displayTier == 1) { //partial hardware acceleration } else { //supports hardware acceleration }
確定了之後,你就可以有選擇性地選擇那些在用戶硬件上工作得很好的功能
10、使用WPF分析工具分析WPF程序
分析WPF程序是理解其行為很重要的一步,市場上有大量現成的WPF程序分析工具,如Snoop,WPFPerf,Perforator和Visual Profiler,其中Perforator和Visual Profiler是WPF Performance Suite的一部分,要了解這些工具的用法,請去它們的項目主頁。
細數改善WPF應用程序性能的10大方法