2010-10-06 2 views
0

Мне нужно поднять событие CollectionChanged объекта ObservableCollection в потоке пользовательского интерфейса.Silverlight & ObservableCollection: Raising CollectionChanged on the UI thread

Я видел различные подходы, начиная от класса-оболочки и заканчивая пользовательской реализацией соответствующего интерфейса.

Есть ли простой способ переопределить INotifyCollectionChanged на ObservableCollection для этого?

Спасибо.

ответ

0

Простейший способ сделать это - просто обеспечить, чтобы вы добавляли/удаляли элементы из коллекции в потоке пользовательского интерфейса. Это может быть сделано с короткой функцией, как это:

private void AddItemsToCollection(List<whatever> newItems) 
{ 
    if (this.Dispatcher.CheckAccess()) 
    { 
     newItems.ForEach(x => myObservableCollection.Add(x)); 
    } 
    else 
     this.Dispatcher.BeginInvoke(new Action<List<whatever>>(AddItemsToCollection), newItems); 
} 
+0

Спасибо, но у меня много происходит в фоновом режиме (например, операции загрузки асинхронных сообщений и т. Д.). Любые другие идеи? – Derick

+0

Я дам ваше предложение. – Derick

+0

@Derick - это красота этой функции - неважно, на какой поток вы ее назовете, она будет маршировать на поток пользовательского интерфейса (если он еще не существует), прежде чем он обновит. – slugster

3

Вы можете подкласс ObservableCollection и переопределить OnCollectionChanged и OnPropertyChanged методы Маршалла события обратно в поток пользовательского интерфейса с использованием correspending диспетчера.

public class DispatcherObservableCollection<T> : ObservableCollection<T> 
{ 
    Dispatcher _dispatcher; 
    public DispatcherObservableCollection(Dispatcher dispatcher) 
    { 
     if (dispatcher == null) 
      throw new ArgumentNullException("dispatcher"); 
     _dispatcher = dispatcher; 
    } 

    protected override void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     if (!_dispatcher.CheckAccess()) 
     { 
      _dispatcher.Invoke(
       new Action<PropertyChangedEventArgs>(base.OnPropertyChanged), e); 
     } 
     else 
     { 
      base.OnPropertyChanged(e); 
     } 
    } 

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     if (!_dispatcher.CheckAccess()) 
     { 
      _dispatcher.Invoke(
       new Action<NotifyCollectionChangedEventArgs>(base.OnCollectionChanged), e); 
     } 
     else 
     { 
      base.OnCollectionChanged(e); 
     } 
    } 
} 
+0

Очень хорошая идея. Тем не менее, он работал только для меня после замены Invoke на BeginInvoke. –