У меня есть настраиваемая одновременная наблюдаемая коллекция, которую я использую как ItemsSource
в настольном приложении WPF.
Чтобы коллекция была "наблюдаемой", я реализовал INotifyCollectionChanged
.Поскольку он «параллельный», то есть может быть изменен из нескольких потоков, я вызываю событие CollectionChanged
, используя System.Windows.Threading.Dispatcher
(как предложено в документах).
Поскольку я хочу, чтобы элементы пользовательского интерфейса былиобновленный в реальном времени, например, пересортировать список при изменении свойства (он же «лайв шейпинг»), я также реализовал ICollectionViewFactory
для создания требуемого представления с его настройками, например, SortDescriptions
.
Рассмотримследующий поток кода - все в потоке пользовательского интерфейса / диспетчера:
- Я создаю коллекцию.
- Я добавляю элементы и вызываю соответствующие события
CollectionChanged
. - Я загружаю
Window
с ListBox
и связываю его с коллекцией.
У меня есть три версии функции, которая вызывается всякий раз, когда изменяется внутренний список (моей пользовательской коллекции):
Версия 1 (с CheckAccess
и InvokeAsync
)
private void _notify(NotifyCollectionChangedEventArgs args)
{
if (_dispatcher.CheckAccess())
{
CollectionChanged?.Invoke(this, args);
}
else
{
_dispatcher.InvokeAsync(() => CollectionChanged?.Invoke(this, args));
}
}
Версия 2 (без CheckAccess
и InvokeAsync
)
private void _notify(NotifyCollectionChangedEventArgs args)
{
_dispatcher.InvokeAsync(() => CollectionChanged?.Invoke(this, args));
}
Версия 3 (без CheckAccess
и Invoke
)
private void _notify(NotifyCollectionChangedEventArgs args)
{
_dispatcher.Invoke(() => CollectionChanged?.Invoke(this, args));
}
Версии 1 и 3 работают нормально, но в Version 2 все элементы отображаются дважды в «Списке».
Это выглядит примерно так:
- Если я нахожусь в потоке пользовательского интерфейса и звоню
Dispatcher.InvokeAsync
, вызов добавляется в «конец сообщения пользовательского интерфейса».pump "- без потока, ожидающего результата. - Элемент пользовательского интерфейса привязывает себя к коллекции, создает представление и заполняет его внутренний источник добавленными элементами.
- " Позже ", затемКогда насос обрабатывается далее, отправленные события вызываются и прослушиваются, и
CollectionView
добавляет элементы к его источнику, создавая дублированные записи.
И я (думаю, я) понимаючто в версии 1 события запускаются (и ожидаются) до того, как элемент UI существует, поэтому нет никаких проблем, касающихся CollectionView
.
Но почему / как делает версию 3 (с Invoke
) работаешь?То, как код ведет себя по-другому, чем при использовании InvokeAsync
, заставляет меня думать, что он должен заблокироваться, потому что он ожидает вызова, который должен быть обработан «дальше по своей собственной рассылке сообщений», но, очевидно, это не так.Invoke
внутренне делает что-то вроде CheckAccess
?