2010-09-21 91 views
5

今天早上我一直在和一个“慢”的WPF组合框作战,并且很想看看有没有人有调试这样的问题的提示。使用数据绑定诊断性能问题WPF组合框

比方说,我有两个组合框,A和B.当A改变时,B中的项目也改变。该组合框都有各自的SelectedItem和数据绑定的ItemsSource像这样:

<ComboBox Grid.Column="1" ItemsSource="{Binding Names}" SelectedItem="{Binding CurrentName, Mode=TwoWay}" Margin="3" MinWidth="100" /> 
<ComboBox Grid.Column="1" Grid.Row="1" ItemsSource="{Binding SubNames}" SelectedItem="{Binding CurrentSubName, Mode=TwoWay}" Margin="3" MinWidth="100" /> 

每当B中的列表需要改变,我通过清除子名做到这一点,然后重新添加基础上,在的SelectedItem A.这是项因为用新的ObservableCollection<string>覆盖子名称会破坏数据绑定。

一台计算机上的所有内容都按照您的预期运行。选择A,然后单击B并立即弹出新项目。在另一台计算机上,当我执行此操作时,在渲染ComboBox之前暂停多达012秒。项目数量完全相同。一个不同之处在于,在慢速的机器上,有硬件通信的背景。我冻结了所有这些线程,并没有帮助。

我最大的问题是,我无法弄清楚哪里可以开始寻找。我需要在点击ComboBox的时候看看系统在做什么。我正在使用数据绑定,所以我不能在任何地方放置断点。我曾尝试我的子名的声明从

public ObservableCollection<string> SubNames { get; set; } 

改变

private ObservableCollection<string> subnames_ = new ObservableCollection<string>(); 
public ObservableCollection<string> SubNames 
{ 
    get { return subnames_; } 
    set { subnames_ = value; } 
} 

,然后放入getter和setter断点来看看是否有过多的读或写事,但有WASN”任何。

任何人都可以建议下一步为我尝试确定这种放缓的来源吗?我不相信它与ComboBox股票模板有任何关系,如in this article所述。

+1

当您在调试会话之外运行时,您是否仍然可以检查它? – ArielBH 2011-06-01 17:06:13

+1

我忘了所有关于这个问题!我在某处发现了一个帖子,提示它只发生在调试器内部,果然,情况就是如此。但是我已经改变了代码以使用ICollectionView来处理所有事情,而且我认为现在甚至在调试器内部都很快。 – Dave 2011-06-01 17:51:29

+0

您节省了我几个小时的调试时间。我使用CollectionViewSource(和列表),并在调试需要3-4秒。在设置ItemsSource之后打开一个ComboBox,但在调试器之外它运行得更快。感谢您指出了这一点。 – surfen 2012-03-18 11:53:04

回答

2

尽管这可能不会直接回答你的问题,但一个建议是不直接绑定到ObservableCollection。由于集合在处理其内容时可能引发大量事件,因此最好将ItemsControl绑定到表示ObservableCollection的ICollectionView,并且在更新集合时使用ICollectionView.DeferRefresh()

我通常做的是我从ObservableCollection中派生出一个类,它公开了一个DefaultView属性,它懒惰地实例化了对应于该集合的ICollectionView。然后我将所有ItemsControl绑定到collection.DefaultView属性。然后,当我需要集合中刷新或以其他方式操纵的项目,我用:

using (collection.DefaultView.DeferRefresh()) { 
    collection. // add/remove/replace/clear etc 
} 

这将刷新绑定控件通过DeferRefresh()返回的对象已被释放之后。

另请注意,WPF中的绑定机制有一个默认的TraceSource,您可以使用它来收集有关绑定本身的更多信息;它不跟踪的时候,所以我不知道那是多么有用,但你可以激活它:

System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Verbose; 

(或者你喜欢的任何其他职等)。

+0

感谢您的建议。有趣的是,我遇到了一个与你所说的直接相关的问题 - 太多的事件被解雇了,而且两者之间的依赖关系,我陷入了奇怪的循环循环中,试图更新然后主要的组合框会导致第二个奇怪的事情发生。我会查看ICollectionView,奇怪的是,我已经使用它,但不记得它的任何内容。 :) – Dave 2010-09-21 20:57:57

+0

对于从组合框A中选择项目会改变组合框B的全部内容的情况,您能推荐任何一般策略吗?我通常将Clear()和Add()添加到一个ObservableCollection中,但是正如您所指出的那样,更好地控制被触发的事件是很好的。我采取了一个中间步骤,并试图使用ICollectionView - 我使用GetDefaultView()作为重新创建组合框B中显示的数据的手段,但它不能这样工作 - 原始内容仍然存在。任何想法我在这里失踪?我尝试了刷新(),并没有帮助。 – Dave 2010-09-23 05:25:07

+0

嗯...那么。我通常做的是在我的ViewModel中有一个ICollectionView属性,并在第一次访问时将它实例化为一个ListCollectionView实例,它封装了也是ViewModel一部分的ObservableCollection。为了简化所有这些,我扩展了ObservableCollection在一个名为DefaultView的属性中自动执行它;现在我可以在ViewModel中公开ObservableCollection并在需要时将其绑定到XAML中的DefaultView属性。这样ICollectionView应该在它后面的集合发生变化时自动进行同步。 – 2010-09-23 08:56:30