Как работает EnableCollectionSynchronization? - PullRequest
0 голосов
/ 02 июля 2019

Есть несколько постов, в которых объясняется использование BindingOperations.EnableCollectionSynchronization. Например. BindingOperations.EnableCollectionSynchronization mystery in 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

Справочная информация: я иногда испытываю InvalidOperationExpetions «коллекция была изменена» при выполнении запросов LINQ для часто изменяемой ObservableCollection. Это привело меня к разрушению предыдущего примера. Тогда я обнаружил, что мое предположение о том, как работает EnableCollectionSynchronization, неверно.

1 Ответ

1 голос
/ 02 июля 2019

Вы должны синхронизировать все доступ к коллекции с использованием той же блокировки, т. Е. Вы должны заблокировать вызов Add:

lock (itemsLock)
    items.Add("foo");

Документация довольно ясна в этом:

Чтобы использовать коллекцию в нескольких потоках, одним из которых является поток пользовательского интерфейса, которому принадлежит ItemsControl, приложение выполняет следующие обязанности:

  • Выберите механизм синхронизации.
  • Синхронизируйте все доступ из приложения к коллекции с использованием этого механизма.
  • Позвоните EnableCollectionSynchronization, чтобы сообщить WPF о механизме.
  • ...
...