Пользовательский интерфейс медленно обновляет ObservableCollection <T>в элементе управления TreeView - PullRequest
2 голосов
/ 06 июня 2011

Сценарий

У меня есть TreeView, который связан с ObservableCollection<T>. Коллекция изменяется каждый раз, когда конечный пользователь изменяет свои фильтры. Когда пользователи изменяют свои фильтры, выполняется обращение к базе данных (занимает 1-2 мс) и возвращаемые данные анализируются для создания иерархии. У меня также есть некоторый XAML, который обеспечивает расширение каждого TreeViewItem, что является частью проблемы. Имейте в виду, что я изменяю только ~ 200 объектов с максимальной глубиной узла 3. Я ожидаю, что это мгновенно.

Проблема

Проблема в том, что всякий раз, когда фильтры модифицируются и иерархия TreeView изменяется, пользовательский интерфейс зависает на ~ 1 секунду.

Вот XAML, ответственный за создание иерархии TreeView.

<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>?

Частичное решение

С чем Х.Б. сказал и реализует BackgroundWorker обновление гораздо более плавным.

Ответы [ 2 ]

6 голосов
/ 06 июня 2011

Проблема, вероятно, в цикле 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; }
}

- это плохо, вы можете перезаписать список, и привязка прекратится, потому что в установщике не сработало событие PropertyChanged .

Если вы используете ObservableCollection, он обычно используется так:

private readonly ObservableCollection<HierarchyViewModel> _hierarchy =
            new ObservableCollection<HierarchyViewModel>();
public ObservableCollection<HierarchyViewModel> Hierarchy
{
    get { return _hierarchy; }
}
1 голос
/ 31 июля 2013

Самое простое, что нужно сделать, это отсоединить элемент, к которому вы привязаны, внести все необходимые изменения в список, а затем снова присоединить его.

Например, задайте для TreeSviews ItemsSource значение NULL / NOTHING, просмотрите каждый для каждого из них, а затем установите ItemsSource обратно в _hierarchy. Ваши добавления будут мгновенными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...