我今天早上一直在和一个“慢”WPF ComboBox作战,并且很想知道是否有人有调试此类问题的提示。
假设我有两个ComboBox,A和B.当A改变时,B中的项也会改变。 ComboBox每个都有这样的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中的列表需要更改时,我通过清除子名称,然后根据A中的SelectedItem重新添加条目来完成此操作。这样做是因为用新ObservableCollection<string>
覆盖子名称会破坏数据绑定。
一台计算机上的所有内容都按照您的预期运行。选择A,然后单击B并立即弹出新项目。在另一台计算机上,当我执行此操作时,在呈现ComboBox之前最多会有 5秒暂停。项目数量完全相同。一个不同之处在于,在慢速机器上,后台正在进行硬件通信。我冻结了所有这些线程并没有帮助。
我最大的问题是我无法弄清楚在哪里开始寻找。我需要查看系统在点击ComboBox时正在做什么。我正在使用数据绑定,所以我无法在任何地方放置断点。我确实尝试从
更改我的SubNames声明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中放置断点以查看是否有过多的读取或写入,但没有。
有人可以建议我下一步尝试确定这种放缓的来源吗?我不相信它与ComboBox库存模板有任何关系,如in this article所述。
答案 0 :(得分:2)
虽然这可能不直接回答你的问题,但一个建议是不直接绑定到ObservableCollection。由于集合在操作其内容时可能会引发大量事件,因此最好将ItemsControl绑定到表示ObservableCollection的ICollectionView,并在更新集合时使用ICollectionView.DeferRefresh()
。
我通常做的是创建一个派生自ObservableCollection的类,该类公开DefaultView
属性,该属性懒惰地实例化与集合对应的ICollectionView。然后我将所有ItemsControls绑定到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;
(或您喜欢的任何其他级别)。