ObservableCollection <T>и OnCollectionChanged - PullRequest
       18

ObservableCollection <T>и OnCollectionChanged

1 голос
/ 26 августа 2010

Я изучал ObservableCollections в WPF, и что-то мне не понятно. Я понимаю, что если я привяжу элемент управления к ObservableCollection и коллекция изменится, этот элемент будет отражать изменения. Мои вопросы:

  • ObservableCollection реализует INotifyCollectionChanged, который является просто событием, CollectionChanged. Это событие должно запускаться всякий раз, когда коллекция меняется, но кто подписывается на это событие? Это делается автоматически при создании привязки к коллекции?

  • Я смотрел на ObservableCollection с помощью Reflector и пытался увидеть, когда происходит событие CollectionChanged. Однако я не мог найти, где это делается. Например, я хотел посмотреть, когда он был запущен, когда я добавил новый элемент в коллекцию. Add (...) реализован в базовом классе ObservableCollection, Collection, но Collection не реализует INotifyCollectionChanged, поэтому я не понимаю, как связанные элементы управления уведомляются об изменении.

Я предполагаю, что многое из этого решено под прикрытием, но любая информация очень ценится.

Ответы [ 5 ]

3 голосов
/ 26 августа 2010

Чтобы ответить на ваш первый вопрос: все начинается внутри свойства "Items" класса ItemContainerGenerator (экземпляр которого у всех объектов ItemsControl есть). Если вы посмотрите на установщик для указанного свойства «Items», то увидите, что у него есть специальная логика, которая проверяет, имеет ли данный IList тип INotifyCollectionChanged, и он присоединит прослушиватель событий.

ItemContainerGenerator.Items свойство:


internal IList Items
{
    get
    {
        return this._items;
    }
    set
    {
        if (this._items != value)
        {
            INotifyCollectionChanged source = this._items as INotifyCollectionChanged;
            if ((this._items != this.Host.View) && (source != null))
            {
                CollectionChangedEventManager.RemoveListener(source, this);
            }
            this._items = value;
            source = this._items as INotifyCollectionChanged;
            if ((this._items != this.Host.View) && (source != null))
            {
                CollectionChangedEventManager.AddListener(source, this);
            }
        }
    }
}

Это действительно не имеет ничего общего с привязками. Смотрите, если у вас есть следующий код, который вообще не использует привязки, уведомление об изменении коллекции все равно будет работать:

<Window x:Class="DynamicObjectTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <Button Click="Button_Click">click</Button>
            <ListBox x:Name="listBox"/>
        </StackPanel>
    </Grid>
</Window>

public partial class MainWindow : Window
    {
        ObservableCollection items = new ObservableCollection();

        public MainWindow()
        {
            InitializeComponent();

            this.listBox.ItemsSource = items;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            items.Add("A");
        }
    }
1 голос
/ 26 августа 2010

Это событие должно запускаться всякий раз, когда коллекция изменяется, но кто подписывается на это событие? Это делается автоматически при создании привязки к коллекции?

Объект Binding подписывается на события CollectionChanged и / или PropertyChanged источника.

1 голос
/ 26 августа 2010

Простой простой английский ответ:

ObservableCollections обновляет элементы управления, к которым они привязываются при добавлении или удалении объектов из коллекций.

Они НЕ обновляют привязку данных при изменении объектов в коллекции.

0 голосов
/ 26 августа 2010

@ Ответ Гранта Крофтона указывает, где "мясо и картофель" из INotifyCollectionChanged находится внутри ObservableCollection<T>. Однако, чтобы ответить на ваш первый вопрос, вы должны прочитать о WPF и Binding Sources .

Обычно, когда вы связываете объект в WPF, он проверяется на наличие определенных «контрактов», одним из которых является INotifyCollectionChanged. WPF обрабатывает присоединение к событию и получение уведомлений. Затем Control определяет, как реагировать при получении уведомления об обновлении одного из его объектов DependencyProperty.

Интересно, что WPF использует представление связывания, а не сам сборник в привязке:

WPF никогда не связывается напрямую с коллекцией. Если вы указываете коллекцию в качестве источника привязки, WPF фактически связывается с представлением коллекции по умолчанию. Для получения информации о представлениях по умолчанию см. Обзор привязки данных .

0 голосов
/ 26 августа 2010

Отражая .Net 3.5, вызовы метода Add () Collection InsertItem:

public void Add(T item)
{
    //...
    int count = this.items.Count;
    this.InsertItem(count, item);
}

InsertItem () переопределяется в ObservableColletion , который выполняет уведомление:

protected override void InsertItem(int index, T item)
{
    this.CheckReentrancy();
    base.InsertItem(index, item);
    this.OnPropertyChanged("Count");
    this.OnPropertyChanged("Item[]");
    this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...