今天早上,我一直在与“慢速” WPF ComboBox进行斗争,很想看看是否有人有调试此类问题的技巧。
假设我有两个ComboBox,A和B。当A更改时,B中的项目也更改。每个组合框都有其SelectedItem和ItemsSource数据绑定(bind),如下所示:
<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中的列表需要更改时,我都会通过清除SubName,然后基于A中的SelectedItem重新添加条目来完成此操作。之所以这样做,是因为用新的
ObservableCollection<string>
覆盖SubName会破坏数据绑定(bind)。一台计算机上的所有内容均按预期运行。选择A,然后单击B,新项目立即弹出。在另一台计算机上,执行此操作时,在呈现ComboBox之前最多需要 5秒暂停。项目数完全相同。一个区别是,在速度较慢的计算机上,硬件通信在后台进行了一些操作。我卡住了所有这些线程,但无济于事。
我最大的问题是,我什至不知道从哪里开始寻找。我需要在单击ComboBox时查看系统在做什么。我正在使用数据绑定(bind),因此无法在任何地方放置断点。我确实尝试将我的SubName声明从更改为
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中设置断点,以查看是否发生了过多的读取或写入操作,但没有任何中断。
谁能建议我下一步尝试确定这种放缓的根源吗?如in this article所述,我认为它与ComboBox库存模板无关。
最佳答案
尽管这可能无法直接回答您的问题,但建议之一是不要直接绑定(bind)到ObservableCollection。由于集合在处理其内容时会引发很多事件,因此最好将ItemsControl绑定(bind)到表示该ObservableCollection的ICollectionView上,并在更新集合时使用ICollectionView.DeferRefresh()
。
我通常要做的是从ObservableCollection派生一个类,该类公开DefaultView
属性,该属性懒惰地实例化与该集合对应的ICollectionView。然后,将所有ItemsControls绑定(bind)到collection.DefaultView属性。然后,当我需要刷新或以其他方式操纵集合中的项目时,可以使用:
using (collection.DefaultView.DeferRefresh()) {
collection. // add/remove/replace/clear etc
}
仅在处置了
DeferRefresh()
返回的对象之后,才刷新绑定(bind)的控件。还应注意,WPF中的绑定(bind)机制具有默认的TraceSource,可用于收集有关绑定(bind)本身的更多信息。它不会跟踪时间,因此我不确定这有多有用,但是您可以使用以下方法激活它:
System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Verbose;
(或您喜欢的任何其他级别)。