2009-06-16 118 views
2

我正在使用MVVM構建wpf應用程序。我的ViewModels僱傭的延遲加載象下面這樣:WPF數據綁定性能

public class AssignmentsViewModel 
{ 

    List<AssignmentViewModel> _Assignments; 
    public List<AssignmentViewModel> Assignments 
    { 
     get 
     { 
      if (_Assignments == null) 
       _Assignments = new List<AssignmentViewModel>(Data.GetAssignments()); 
      return _Assignments; 
     } 
     set { _Assignments = value; } 
    } 
} 
public class AssignmentViewModel 
{ 
    List<NoteViewModel> _Notes; 
    public List<NoteViewModel> Notes 
    { 
     get 
     { 
      if (_Notes == null) 
       _Notes = new List<NoteViewModel>(Data.GetNotes()); 
      return _Notes; 
     } 
     set { _Notes = value; } 
    } 
} 

視圖已經在ListView並與一個DataTemplate一個ListBox中的注意事項的AssignmentViewModels。

當我顯示其中一個具有160個項目的AssignmentViewModels時,需要1000毫秒才能加載。我認爲這是因爲從擁有150萬行的數據庫表抓取Notes屬性。我檢查了它,只用了60ms來填充Notes列表。所以我猜測這是將160個項目加載到列表框中的數據綁定。但是,情況並非如此,因爲listBoxes虛擬化了他們的內容(我對它進行了窺探並驗證了這些項目位於虛擬化的堆棧面板中)。

所以我很茫然,我不知道如何找出額外的940毫秒。

我能做些什麼來跟蹤這個問題?性能是關鍵,我不知道如何改進它。

回答

3

不知道用戶界面是什麼樣的,有可能是用戶界面的某些東西正在減慢它像BitmapEffects的大量使用。

另外,您可能希望將列表切換到ObservableCollection,如binding to that can be significantly faster then a List

也有一些很好的performance profiling工具可以幫助你。

+0

非常感謝這些性能分析鏈接。我需要了解如何使用它們。 :) – Jose 2009-06-16 18:17:26

2

我們能否看到您的XAML?

如果您的列表框位於堆棧面板(或類似控件)內,則列表框不會虛擬其條目。

這將虛擬化:

<Grid> 
    <Grid.RowDefinitions> 
    <RowDefinition Height="Auto" /> 
    <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 

    <Label Grid.Row=0>Your label here</Label> 
    <ListBox Grid.Row=1 Your properties here... /> 

</Grid> 

這不會:

<StackPanel> 
    <Label>Your label here</Label> 
    <ListBox Your properties here... /> 
</StackPanel> 

的StackPanel的列表框將呈現它的最大高度取決於StackPanel的滾動內。 (沒有虛擬化)

在網格中,列表框將渲染到網格行高並使用它自己的滾動查看器。 (虛擬化)

您也可以在列表框中設置Height或MaxHeight屬性,而不是將其放置在網格中,但是如果使用堆棧面板,我懷疑需要某種類型的自動大小。

請注意,您不能通過將堆疊面板放置在網格中進行作弊;你的列表框必須能夠從某處獲得最大高度。

0

你有沒有嘗試無延遲加載測試嗎?

此外,您的項目的DataTemplates/Views有多複雜?嘗試使用簡單的TextBlock表示來運行測試,以確保它不是您的視圖有多複雜。

0

我會再看看SQL,並確保您的集合正在填充。在列舉結果之前,L2S不會實際填充。

private IEnumerable<Thing> Method1() 
{ 
    return _db.Things.Where(t => t.ID > 500); 
} 
private void Method2() 
{ 
    var things = Method1(); // here, 'things' doesn't really contain anything 
          // even though you've already done the db fetch 
    foreach (var thing in things) // 'things' gets populated here. 
    { 
     // do something 
    } 
} 

例如:在返回數據後立即致電.ToList()。您會在數據層中看到更多的活動,這些活動可能直到您的業務或UI層纔會發生。

+0

是的,我明白,GetNotes函數遍歷列表。 – Jose 2009-06-16 17:31:17

0

我想通了。我有一個需要進行文本編輯的文本塊,因爲它有時非常大。我明確地設置它的寬度(以便它會包裝)在數據模板內部,並且由於某種原因導致ListBox中的VirtualizingStackPanel實現列表中的所有項目。我重新修改它,使其適合像這樣的網格。

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="3*" /> 
     <ColumnDefinition Width="*" /> 
    </Grid.ColumnDefinitions> 
    <Grid Grid.Column="0"> 
     .... 
    </Grid> 
    <ListBox Grid.Column="1" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" > 
     ...//DataTemplate 
    </ListBox> 
</Grid> 

這導致列表框快速加載。感謝您的回答,他們帶我走上了正確的道路。