Reputation: 21
I'm developing WPF application using MVVM, Code-First and the repository pattern. I need to have a background task, which processes webserver requests from clients and saves new data into database.
The problem is each ViewModel has a property (ObservableCollection), which gets Repository.GetObservableCollection(). So each ViewModel has a repository instance, which has the same DbContext (so I don't get DbException when saving complex entities). This DbContext is long-living until the end of app in each repo and is injected from MainViewModel to the contructors of VMs.
When I save new data to the database from the background task, the GUI doesn't update, because I'm using different DbContext there (I have to due to concurrent requests):
using (var db = new DbContextManager())
{
var client = new Client();
db.Client.Add(client);
db.SaveChanges();
}
There are two ways, which I tried:
When saving new data into the DB, also add the entities to Repositories via.
Application.Current.Dispatcher.Invoke ( () => { _clientRepository.Add(client); } );
That way, the entities appear in GUI immidiately, but there's also slight lag (when moving window) and I can't update existing entity's property.
The question is how can I refactor this to allow both GUI and background interaction with entities. How to properly combine repository and MVVM?
Upvotes: 2
Views: 1286
Reputation:
Don't directly link a ViewModel entity with a DB DataContext
.
You need to define an ObservableCollection
in the ViewModel and its binding in the XAML.
After that you'll asynchronously update the collection by calling functions from your persistence layer. So you better off with a LoadAsync
, alternatively you could wrap your DB retrieval into a Task. This approach will work because await
will capture the SynchronizationContext
of the UI thread and will update your component in the UI thread.
The actual DataContext
has to be hidden in that persistence layer and must remain unknown to the ViewModel.
if I don't pass DbContext to the ViewModels (which in turn pass it to its Repository), how do I get the context to the repository, so I can call
point void LoadAll() {
context.Set<T>().Load();
}
and
public ObservableCollection<T> GetObservableCollection() {
return context.Set<T>().Local;
}
As per my answer, the ViewModel can call the persistence layer function to load the collection, (it's not even necessary that the type returned from the persistence layer is observable).
The point is that you won't return void
and you'll possibly use a LoadAsync
so that you can await
it when you assign the returned data to the underlying collection of your ViewModel property.
so I have to use
Dispatcher.Invoke
to interact with repos/viewmodels
No, don't use Dispatcher.Invoke
to interact with the repository DB context. Make the interaction with the DB async. Notice that Dispatcher.Invoke
is only for the UI layer.
Upvotes: 1
Reputation: 44
Do you use the binding mechanism? You could update your collection after changing it (assuming that your VM implements INotifyPropertyChanged
interface).
Upvotes: 0