Чтобы ответить на ваш первый вопрос: все начинается внутри свойства "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");
}
}