Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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.

Basically, my save command generates an event, that notifies a collection view model, that an Item has been added and that the item should be added to its own ObservableCollection.

At this point, I get the usual exception saying I can NOT update an ICollection on a different thread. I have tried creating a new list type that calls Dispatcher.Invoke, however this still generates the same exception.

I was wondering whether anyone else has any suggestions on how best to tackle this?

So currently I have a class that Inherits from ObservableCollection:

public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    public ThreadSafeObservableCollection(List<T> collection)
        : base(collection)
    {
        dispatcher = Dispatcher.CurrentDispatcher;
        rwLock = new ReaderWriterLock();
    }

    protected override void InsertItem(int index, T item)
    {
        if (dispatcher.CheckAccess())
        {
            if (index > this.Count)
                return;
            LockCookie c = rwLock.UpgradeToWriterLock(-1);
            base.InsertItem(index, item);
            rwLock.DowngradeFromWriterLock(ref c);
        }
        else
        {
            object[] obj = new object[] { index, item };
            dispatcher.Invoke(
                DispatcherPriority.Send, 
                (SendOrPostCallback)delegate { InsertItemImpl(obj); }, 
                obj);
        }
    }

I then have a view model class that has a background worker which carries out the save.

Once the save is complete, an event is fired to another view model to update its list.

    protected override void OnObjectAddedToRepository(object sender, ObjectEventArgs<cdAdministrators> e)
    {
        Dispatcher x = Dispatcher.CurrentDispatcher;
        var viewModel = new AdministratorViewModel(e.EventObject, DataAccess);
        viewModel.RecentlyAdded = true;
        viewModel.ItemSelected += this.OnItemSelected;
        this.AllViewModels.Add(viewModel);
        RecentlyAddedViewModel = viewModel;

        OnPropertyChanged(null);
    }

Both lists are created by a separate background worker thread.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
425 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...