2012-12-14 66 views
5

我在我的應用程序中使用巨大的表格來顯示數據。數據顯示在兩個嵌套的UniformGrid中。 UniformGrids是ItemsControls中的ItemPanels,並綁定到一些ViewModels。見下面的圖片和一些示例XAML碼:如何處理巨大的UniformGrid中的性能?

view and viewmodel http://img593.imageshack.us/img593/8825/stackoverflowuniformgri.png

<!-- The green boxes --> 
<ItemsControl ItemsSource="{Binding BigCells}"> 

    <ItemsControl.ItemPanel> 
    <PanelTemplate> 
     <UniformGrid /> 
    </PanelTemplate> 
    </ItemsControl.ItemPanel> 

    <ItemsControl.ItemTemplate> 
    <DataTemplate> 

     <!-- The blue boxes --> 
     <ItemsControl ItemsSource="{Binding SmallCells}"> 
     <ItemsControl.ItemPanel> 
      <PanelTemplate> 
      <UniformGrid /> 
      </PanelTemplate> 
     </ItemsControl.ItemPanel> 
     </ItemsControl> 

    </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

現在,我想我的觀點是可調整大小的,但是這並不在所有的,因爲每一個小方塊的佈局計算表現良好。
這至少可以使箱子大小隻做一次,因爲它對所有箱子都是相同的。

什麼是在WPF /顯示大量控件的最佳實踐,我可以從哪裏開始優化?關鍵字已經幫助我繼續發現WPF中UniformGrid的性能優化。

回答

8

我在同一時間使用大量WPF DataGrid時遇到類似問題。它終於來到了兩個主要問題:

  • 資源字典
  • 綁定

資源字典

那些可以成爲主要的瓶頸,如果你使用不小心,基本的WPF功能。

就我而言,在ItemsControl這是包含我DataGrids一個單一的邏輯滾動,我是越來越像10個百萬來電GetValueGetValueWithoutLock上的ResourceDictionary。處理時間超過1秒。

  • 動態資源檢索:如果你有ControlTemplates,一般多放在一些資源字典資源,您通過{DynamicResource ...}訪問它們,刪除它們

    ResourceDictionary訪問該主號碼是由不同的源引起的。有一些靜態的地方,直接訪問它們。

  • 樣式獲取:如果您在使用的不同Visual上沒有樣式,或者如果您有樣式但未設置FrameworkElement.OverridesDefaultStyle屬性,則WPF將嘗試在所有資源中找到與該控件匹配的樣式,在對資源詞典的大量訪問中。爲避免這種情況,請務必覆蓋控件的所有控件模板,並在每個控件上設置Style={x:Null}(如果您需要控件的樣式,請將其設置在控件上,並添加OverridesDefaultStyle = true
  • Implicit DataTemplates:隱式數據模板非常有用,但遠不是免費的。在查找要應用的DataTemplate時,WPF將再次瀏覽資源字典以查找與您的ViewModels類型匹配的DataTemplate。解決方法是使用DataTemplate選擇器爲綁定到ViewModel的每個控件添加一個優化方法,以檢索正確的DataTemplate。 (我個人有一些dataTemplate的靜態字段,我只從resourceDictionary中檢索一次,並且根據需要返回一個優化的DataTemplateSelector。)

綁定

綁定是非常有用的,但價格昂貴,內存明智和性能明智的。在一個非常明智的環境中 - 從演出的角度來看 - 你不能只使用它們而不小心。例如,綁定可以爲每個綁定對象創建最多3個WeakReference,可以使用反射等。最後,我最終刪除了DataContext的PropertyChanged事件中幾乎所有綁定和插入的事件處理函數。當我的控件上的DataContext更改(您有DataContextChanged事件)時,我測試我的DataContext是否支持INotifyPropertyChanged,並且如果是這種情況,我在需要時附加事件處理程序PropertyChanged事件和更新屬性。 (我只有一種綁定方式,所以這就是我選擇這種做法的原因,但還有其他解決方案)。

在使用MVVM和WPF時,看起來令人沮喪的是沒有使用綁定,但實際上我沒有辦法優化綁定。

最後一件事:如果你有Freezable對象(如畫筆),請不要猶豫Freeze他們,如果你可以。

這些建議可以幫助您優化代碼。您將需要一個分析器(我總是建議使用dotTrace,因爲這是我用過的最好的分析器)來監視實際發生的情況並根據結果進行調整。

祝你好運!

+0

感謝您的詳細解答。它已經包含了我可以在我的應用程序中改進的一些要點(freezables,默認樣式覆蓋)。我會稍後檢查並報告。 –

+0

當然,讓我知道它是怎麼回事!對我來說,這實際上是一個很好的練習,因爲我必須在我的博客上寫一篇演示文章:) – Sisyphe

+0

我們有很多資源詞典,應用程序仍然非常快。我們接觸它的方式是爲一個資源創建一個資源字典(如樣式,矢量,畫筆等),然後從每個視圖中只引用所需的資源字典。問題在於統一網格本身,因爲它沒有虛擬化。 – adminSoftDK

4

如果您確定所有想要的尺寸相同,請始終制作您自己的UniformGrid課程並覆蓋MeasureOverride以僅測量一個孩子。我最終可能會在我當前的項目中使用一些大小相同的內部控件的UniformGrid,所以你的想法很吸引我,我決定嘗試一下:

我用Petzold的UniformGridAlmost類作爲靈感,但是從UniformGrid而不是Panel,所以行和列的depdendency屬性不需要重複。 UniformGrid似乎沒有公佈所計算的行數和列數到其派生類,所以我借用Silverlight's UniformGrid class的實現並使用UpdateComputedValues方法。

的在我的課MeasureOverride看起來像這樣

protected override Size MeasureOverride(Size sizeAvailable) 
    { 
    if (InternalChildren.Count == 0) 
    { 
     return new Size(0, 0); 
    } 

    UpdateComputedValues(); 

    // Calculate a child size based on uniform rows and columns. 
    Size sizeChild = new Size(sizeAvailable.Width/ComputedColumns, 
           sizeAvailable.Height/ComputedRows); 

    // Assume children will measure to at least a comparable size. 
    UIElement child = InternalChildren[0]; 
    child.Measure(sizeChild); 

    double width = Math.Max(width, child.DesiredSize.Width); 
    double height = Math.Max(height, child.DesiredSize.Height); 
    return new Size(ComputedColumns * width, ComputedRows * height); 
    } 

所以,這裏的踢球,當我用10000點的TextBlocks測試了一個ItemsControl,我UniformGrid的版本是快,但只有一個很小的量(少於1% - 我確認了MeasureOverride的調用速度快了大約95%)。所以這可能沒有幫助,但我想我會分享我的經驗。你觀察到它不需要測量每個盒子來確定你的案例中的統一佈局是真實的,但是這種測量不是讓它陷入困境。我相信那是因爲所有這些控件仍然需要繪製,因此無論如何它們都會被測量。你很可能會從ResourceDictionary/Binding建議中獲得更多。

+0

我剛剛試過這個UniformGridAlmost,在我的情況下,它比標準的統一網格快3倍。所以繪圖時間從20秒降到7秒左右。 – adminSoftDK