我有TreeView
绑定到ObservableCollection<T>
。每次最终用户修改其过滤器时,都会修改该集合。当用户修改他们的过滤器时,会调用数据库(需要1-2ms顶部),并且返回的数据将被解析以创建层次结构。我还有一些XAML确保每个TreeViewItem
都被扩展,这似乎是问题的一部分。请记住,我只修改了200个最大节点深度为3的对象。我希望这是即时的。
问题在于,无论何时修改过滤器并更改TreeView
层次结构,UI都会挂起约1秒钟。
以下是负责创建TreeView
层次结构的XAML。
<TreeView VerticalAlignment="Top" ItemsSource="{Binding Hierarchy}" Width="240"
ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1">
<TreeView.ItemTemplate>
<!-- Hierarchy template -->
<HierarchicalDataTemplate ItemsSource="{Binding Stations}">
<TextBlock Text="{Binding}" />
<!-- Station template -->
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Locates}">
<TextBlock Text="{Binding Name}" />
<!-- Locate template -->
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TicketNo}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
这是更新列表的代码。
public ObservableCollection<HierarchyViewModel> Hierarchy
{
get { return _hierarchy; }
set { _hierarchy = value; }
}
public void UpdateLocates(IList<string> filterIds)
{
_hierarchy.Clear();
// Returns 200 records max
var locates = _locateRepository.GetLocatesWithFilters(filterIds);
var dates = locates.Select(x => x.DueDate);
foreach (var date in dates)
{
var vm = new HierarchyViewModel
{
DueDate = date
};
var groups = locates.Where(x => x.DueDate.Date.Equals(date.Date)).GroupBy(x => x.SentTo);
// Logic ommited for brevity
_hierarchy.Add(vm);
}
}
我也有<Setter Property="IsExpanded" Value="True" />
作为一种风格。我尝试过使用BindingList<T>
并禁用通知,但这没有帮助。
在对ObservableCollection<T>
进行更改时,有关为什么我的用户界面会挂起的任何想法?
H.B.说和实施BackgroundWorker
更新更加流畅。
答案 0 :(得分:6)
问题可能是foreach
循环。每次添加对象时,都会触发CollectionChanged
事件并重建树。
如果您只是清除整个列表并将其替换为新列表,则不希望使用ObservableCollection
,使用List
并触发PropertyChanged
事件数据已满载。
即。只需绑定到这样的属性(需要实现INotifyPropertyChanged
):
private IEnumerable<HierarchyViewModel> _hierarchy = null;
public IEnumerable<HierarchyViewModel> Hierarchy
{
get { return _hierarchy; }
set
{
if (_hierarchy != value)
{
_hierarchy = value;
NotifyPropertyChanged("Hierarchy");
}
}
}
如果设置此属性,将通知绑定。在这里我使用IEnumerable
接口,所以没有人试图只添加项目(绑定不会注意到)。但这只是一个建议,可能适用于您的特定情况,也可能不适用。
(另见sixlettervariable的好评)
只是旁注,这段代码:
public ObservableCollection<HierarchyViewModel> Hierarchy
{
get { return _hierarchy; }
set { _hierarchy = value; }
}
很糟糕,您可以覆盖列表,绑定会中断,因为setter中没有触发PropertyChanged事件。
如果使用ObservableCollection,通常使用如下:
private readonly ObservableCollection<HierarchyViewModel> _hierarchy =
new ObservableCollection<HierarchyViewModel>();
public ObservableCollection<HierarchyViewModel> Hierarchy
{
get { return _hierarchy; }
}
答案 1 :(得分:1)
最简单的方法是分离您绑定的项目,对列表进行所需的所有更改,然后重新附加。
例如,将treeview ItemsSource设置为NULL / NOTHING,通过你的每个运行,然后将ItemsSource设置回_hierarchy。您的添加将是即时的。