Update an ObservableCollection with a background worker in MVVM

后端 未结 3 661
谎友^
谎友^ 2020-12-10 14:13

Ok, I recently implemented a background worker to perform saving and loading of data.

However, getting this to work on a save command has proved difficult.

B

相关标签:
3条回答
  • 2020-12-10 14:53

    I found a blog post that uses the Dispatcher to manage all of the ObeservableCollection's methods. Here is a snip-it of the code, see the post for the entire class.

    public class DispatchingObservableCollection<T> : ObservableCollection<T>
    {
        /// <summary>
        /// The default constructor of the ObservableCollection
        /// </summary>
        public DispatchingObservableCollection()
        {
            //Assign the current Dispatcher (owner of the collection)
            _currentDispatcher = Dispatcher.CurrentDispatcher;
        }
    
        private readonly Dispatcher _currentDispatcher;
    
        /// <summary>
        /// Executes this action in the right thread
        /// </summary>
        ///<param name="action">The action which should be executed</param>
        private void DoDispatchedAction(Action action)
        {
            if (_currentDispatcher.CheckAccess())
                action();
            else
                _currentDispatcher.Invoke(DispatcherPriority.DataBind, action);
        }
    
        /// <summary>
        /// Clears all items
        /// </summary>
        protected override void ClearItems()
        {
            DoDispatchedAction(() => base.ClearItems());
        }
    
        /// <summary>
        /// Inserts a item at the specified index
        /// </summary>
        ///<param name="index">The index where the item should be inserted</param>
        ///<param name="item">The item which should be inserted</param>
        protected override void InsertItem(int index, T item)
        {
            DoDispatchedAction(() => base.InsertItem(index, item));
        }
    
    0 讨论(0)
  • 2020-12-10 15:01

    Where you've got code which adds the item to the observable collection (presumably in the view model), wrap that Add call in a Dispatcher.BeginInvoke call.

    Admittedly that means the view model needs to know about the dispatcher, which then becomes awkward to test... fortunately it's not too hard to introduce your own IDispatcher interface and use dependency injection in the normal way.

    0 讨论(0)
  • 2020-12-10 15:18

    How about this?

    public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
    {
        private SynchronizationContext SynchronizationContext;
    
        public ThreadSafeObservableCollection()
        {
            SynchronizationContext = SynchronizationContext.Current;
    
            // current synchronization context will be null if we're not in UI Thread
            if (SynchronizationContext == null)
                throw new InvalidOperationException("This collection must be instantiated from UI Thread, if not, you have to pass SynchronizationContext to con                                structor.");
        }
    
        public ThreadSafeObservableCollection(SynchronizationContext synchronizationContext)
        {
            if (synchronizationContext == null)
                throw new ArgumentNullException("synchronizationContext");
    
            this.SynchronizationContext = synchronizationContext;
        }
    
        protected override void ClearItems()
        {
            this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.ClearItems()), null);
        }
    
        protected override void InsertItem(int index, T item)
        {
            this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.InsertItem(index, item)), null);
        }
    
        protected override void RemoveItem(int index)
        {
            this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.RemoveItem(index)), null);
        }
    
        protected override void SetItem(int index, T item)
        {
            this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.SetItem(index, item)), null);
        }
    
        protected override void MoveItem(int oldIndex, int newIndex)
        {
            this.SynchronizationContext.Send(new SendOrPostCallback((param) => base.MoveItem(oldIndex, newIndex)), null);
        }
    }
    
    0 讨论(0)
提交回复
热议问题