WPF数据绑定性能

时间:2009-06-16 16:24:03

标签: wpf performance mvvm

我正在使用MVVM构建一个wpf应用程序。我有viewModels雇佣延迟加载如下:

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; }
    }
}

View在ListView中有AssignmentViewModels,在ListBox中有一个带有datatemplate的Notes。

当我显示其中一个有160个项目的AssignmentViewModel时,需要加载1000毫秒。我认为这是因为Notes属性从数据库表中获取了150万行。我查了一下,填充Notes列表只花了60ms。所以我猜这是将160个项目加载到列表框中的数据绑定。但事实并非如此,因为listBoxes虚拟化了他们的内容(我已经窥探它并验证了这些项目是在Virtualizing stackpanel中)。

所以我不知所措,我不知道如何找出额外的940毫秒。

我可以做些什么来追踪这个?性能是关键,我不知道如何改进它。

5 个答案:

答案 0 :(得分:3)

在不知道UI是什么样的情况下,UI中的某些内容可能会像BitmapEffects的大量使用一样减慢它。

此外,您可能希望将列表切换为ObservableCollection,binding to that can be significantly faster then a List

还有一些可以帮助您的好performance profiling工具。

答案 1 :(得分:2)

我们能看到您的XAML吗?

如果您的列表框位于stackpanel(或类似控件)中,则列表框不会虚拟化其条目。

这将虚拟化:

<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属性,而不是将其放在网格中,但如果您使用的是stackpanel,我怀疑您想要某种类型的自动调整。

请注意,您不能通过将堆叠面板放在网格内来作弊;你的列表框必须能够从某个地方获得最大高度。

答案 2 :(得分:0)

您是否尝试过无延迟加载的测试?

此外,您的DataTemplates / Views对您的商品有多复杂?尝试运行带有简单TextBlock表示的测试,以确保视图的复杂程度。

答案 3 :(得分: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
    }
}

ex:返回数据后立即调用.ToList()。您会在数据层中看到更多活动,这些活动在您的业务或UI层之前可能尚未发生。

答案 4 :(得分:0)

我明白了。我有一个需要文本包装的文本块,因为它有时很大。我在datatemplate中显式设置它的宽度(以便它将包装),并且由于某种原因导致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>

这导致列表框快速加载。感谢您的回答,他们让我走上了正确的道路。