Есть несколько сообщений, объясняющих использование BindingOperations.EnableCollectionSynchronization. Например. BindingOperations.EnableCollectionЗагадка синхронизации в WPF или Использование BindingOperations.EnableCollectionSynchronization
Однако мое понимание «замка» не соответствует поведению следующей демонстрации.
private void Button_Click(object sender, RoutedEventArgs e)
{
var itemsLock = new object();
var items = new ObservableCollection<string>();
BindingOperations.EnableCollectionSynchronization(items, itemsLock);
Task.Run(() =>
{
lock (itemsLock)
{
Debug.WriteLine("task inside lock");
Thread.Sleep(5000);
items.Where(m => m == "foo").ToArray();
}
Debug.WriteLine("task outside lock");
});
Thread.Sleep(1000);
Debug.WriteLine("UI thread add..");
items.Add("foo");
Debug.WriteLine("UI thread add..done");
}
Из-за блокировки я ожидал, что вывод отладки будет таким:
task inside lock
UI thread add..
task outside lock
UI thread add..done
Но я нахожу вывод отладки следующим образом:
task inside lock
UI thread add..
UI thread add..done
task outside lock
Справочная информация: я иногда сталкиваюсь с InvalidOperationExceptions "коллекция была изменена" при выполнении запросов LINQ к часто изменяемой ObservableCollection. Это привело меня к тому, что я разбил его на предыдущий образец. Затем я обнаружил, что мое предположение о том, как работает EnableCollectionSynchronization, неверно.





Вы должны синхронизировать доступ все к коллекции, используя ту же блокировку, т.е. вы должны блокировать вызов Add:
lock (itemsLock)
items.Add("foo");
документация довольно ясно говорит об этом:
To use a collection on multiple threads, one of which is the UI thread that owns the
ItemsControl, an application has the following responsibilities:
EnableCollectionSynchronization, чтобы сообщить WPF о механизме.
Позор мне - должно быть, я был слеп. Почему-то я подумал, что BindingOperations.EnableCollectionSynchronization делает мою ObservableCollection потокобезопасной. Однако все, что он делает, — это совместное использование объекта блокировки с привязкой WPF.