WPF Security ObservableCollection

I have an MVVM setup.

My model periodically calls some service, and then calls an action in the ViewModel, which then updates some of the variables that are displayed in the view.

The variable is ReadOnlyObservableCollection<T> , which has an ObservableCollection<T> that is listening.

The problem is that the model is calling a callback from another thread and thus does not allow me to clear the ObservableCollection<T> from another thread.

So, I thought: use the dispatcher, if we are not in the right thread, call it:

  private void OnNewItems(IEnumerable<Slot> newItems) { if(!Dispatcher.CurrentDispatcher.CheckAccess()) { Dispatcher.CurrentDispatcher.Invoke(new Action(() => this.OnNewItems(newItems))); return; } this._internalQueue.Clear(); foreach (Slot newItem in newItems) { this._internalQueue.Add(newItem); } } 

The code is pretty simple, I think.

The problem is that although I am executing it in the correct thread (I think), it still throws me an exception on .Clear();

Why is this happening? How can I get around this without creating a custom ObservableCollection<T> ?

0
source share
2 answers

I usually initialize the dispatcher used by my view models in the general view model model to ensure that it is a UI thread manager, as will be indicated in the message.

 #region ViewModelBase() /// <summary> /// Initializes a new instance of the <see cref="ViewModelBase"/> class. /// </summary> protected ViewModelBase() { _dispatcher = Dispatcher.CurrentDispatcher; } #endregion #region Dispatcher /// <summary> /// Gets the dispatcher used by this view model to execute actions on the thread it is associated with. /// </summary> /// <value> /// The <see cref="System.Windows.Threading.Dispatcher"/> used by this view model to /// execute actions on the thread it is associated with. /// The default value is the <see cref="System.Windows.Threading.Dispatcher.CurrentDispatcher"/>. /// </value> protected Dispatcher Dispatcher { get { return _dispatcher; } } private readonly Dispatcher _dispatcher; #endregion #region Execute(Action action) /// <summary> /// Executes the specified <paramref name="action"/> synchronously on the thread /// the <see cref="ViewModelBase"/> is associated with. /// </summary> /// <param name="action">The <see cref="Action"/> to execute.</param> protected void Execute(Action action) { if (this.Dispatcher.CheckAccess()) { action.Invoke(); } else { this.Dispatcher.Invoke(DispatcherPriority.DataBind, action); } } #endregion 

Then you can invoke the action in the view model manager as follows:

 this.Execute( () => { this.OnNewItems(newItems); } ); 
+2
source

A clear fix for this issue found on Codeproject- Multi-Threaded ObservableCollection and NotifyCollectionChanged Wrapper

0
source

Source: https://habr.com/ru/post/908911/


All Articles