Подтвердить что ты не робот

Могу ли я каким-то образом временно отключить изменения привязки данных WPF?

У меня есть приложение WPF, которое использует привязки данных MVVM. Я добавляю элементы к ObservableCollection<...>, и довольно многие из них действительно.

Теперь мне интересно, что каждый раз, когда я добавляю его в коллекцию, он мгновенно запускает событие и вызывает лишние накладные расходы? Если да, могу ли я каким-то образом временно отключить уведомления о событиях и вручную запустить его один раз в конце моего кода, чтобы, если я добавлю 10k элементов, он будет запускаться только один раз, а не 10k раз?

Обновление: я попробовал этот класс:

using System;
using System.Linq;
using System.Collections.Specialized;
using System.Collections.Generic;

namespace MyProject
{

    /// <summary> 
    /// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. 
    /// </summary> 
    /// <typeparam name="T"></typeparam> 
    public class ObservableCollection<T> : System.Collections.ObjectModel.ObservableCollection<T>
    {

        /// <summary> 
        /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). 
        /// </summary> 
        public void AddRange(IEnumerable<T> collection)
        {
            foreach (var i in collection) Items.Add(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
        }

        /// <summary> 
        /// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). 
        /// </summary> 
        public void RemoveRange(IEnumerable<T> collection)
        {
            foreach (var i in collection) Items.Remove(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, collection.ToList()));
        }

        /// <summary> 
        /// Clears the current collection and replaces it with the specified item. 
        /// </summary> 
        public void Replace(T item)
        {
            ReplaceRange(new T[] { item });
        }
        /// <summary> 
        /// Clears the current collection and replaces it with the specified collection. 
        /// </summary> 
        public void ReplaceRange(IEnumerable<T> collection)
        {
            List<T> old = new List<T>(Items);
            Items.Clear();
            foreach (var i in collection) Items.Add(i);
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, collection.ToList()));
        }

        /// <summary> 
        /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class. 
        /// </summary> 
        public ObservableCollection() : base() { }

        /// <summary> 
        /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection. 
        /// </summary> 
        /// <param name="collection">collection: The collection from which the elements are copied.</param> 
        /// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception> 
        public ObservableCollection(IEnumerable<T> collection) : base(collection) { }
    }
}

Теперь я получаю эту ошибку:

Дополнительная информация: действия диапазона не поддерживаются.

Ошибка здесь:

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
4b9b3361

Ответ 1

Очень быстрый и простой способ заключается в подклассе ObservableCollection и приостановке уведомлений при вызове AddRange. См. после сообщения в блоге для уточнения.

Ответ 2

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

Таким образом, вы можете добавить все ваши 10k-элементы в какую-нибудь "коллекцию держателей", а после того, как вы закончите, используйте AddRange вашего ObservableColleciton для этого.

Подробнее об этом вы можете найти по этой ссылке:

ObservableCollection Не поддерживает метод AddRange....

или этот тоже

AddRange и ObservableCollection

Ответ 3

Это расширение ObservableCollection легко решает проблему.

Он предоставляет публичное свойство SupressNotification, позволяющее пользователю управлять, когда уведомление CollectionChanged будет подавлено.

Он не предлагает вставку/удаление диапазона, но если уведомление CollectionChanged подавлено, необходимость делать операцию диапазона в коллекции уменьшается в большинстве случаев.

Эта реализация заменяет все подавленные уведомления уведомлением Reset. Это логически разумно. Когда пользователь подавляет уведомление, выполняет массовые изменения и затем повторно активирует его, ему следует отправить уведомление Resent.

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
    private bool _notificationSupressed = false;
    private bool _supressNotification = false;
    public bool SupressNotification
    {
        get
        {
            return _supressNotification;
        }
        set
        {
            _supressNotification = value;
            if (_supressNotification == false && _notificationSupressed)
            {
                this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
                _notificationSupressed = false;
            }
        }
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (SupressNotification)
        {
            _notificationSupressed = true;
            return;
        }
        base.OnCollectionChanged(e);
    }
}