我正在使用MVVM,Code-First和存储库模式开发WPF应用程序。我需要有一个后台任务,它处理来自客户端的Web服务器请求并将新数据保存到数据库中。
问题是每个ViewModel都有一个属性(ObservableCollection),它获取Repository.GetObservableCollection()。因此每个ViewModel都有一个存储库实例,它具有相同的DbContext(因此在保存复杂实体时我不会得到DbException)。这个DbContext长期存在,直到每个仓库中的应用程序结束,并从MainViewModel注入虚拟机的构造器。
当我从后台任务将新数据保存到数据库时,GUI不会更新,因为我在那里使用不同的DbContext(我必须由于并发请求):
using (var db = new DbContextManager())
{
var client = new Client();
db.Client.Add(client);
db.SaveChanges();
}
我尝试了两种方法:
将新数据保存到数据库时,还要通过实时将实体添加到存储库。
Application.Current.Dispatcher.Invoke ( ()=> { _clientRepository.Add(客户端); } );
这样,实体会立即出现在GUI中,但也有轻微的滞后(移动窗口时),我无法更新现有实体的属性。
问题是如何重构这一点以允许GUI和后台与实体交互。如何正确组合存储库和MVVM?
答案 0 :(得分:0)
你使用绑定机制吗?您可以在更改后更新集合(假设您的VM实现了INotifyPropertyChanged
接口)。
答案 1 :(得分:0)
不要将ViewModel实体与数据库DataContext
直接链接。
您需要在ViewModel中定义ObservableCollection
及其在XAML中的绑定。
之后,您将通过调用持久层中的函数来异步更新集合。所以你最好使用LoadAsync
,或者你可以将数据库检索包装成一个Task。这种方法可行,因为await
将捕获UI线程的SynchronizationContext
,并将在UI线程中更新您的组件。
实际DataContext
必须在该持久层中隐藏,并且必须保持 unknown 到ViewModel。
如果我没有将DbContext传递给ViewModel(后者又传递给它) 它的存储库),如何获取存储库的上下文,所以我可以 调用
point void LoadAll() {
context.Set<T>().Load();
}
和
public ObservableCollection<T> GetObservableCollection() {
return context.Set<T>().Local;
}
根据我的回答,ViewModel可以调用持久层函数来加载集合(它甚至不需要从持久层返回的类型是可观察的)。
关键是您不会返回void
并且您可能会使用LoadAsync
,以便在将返回的数据分配给基础集合时可以await
您的ViewModel属性。
所以我必须使用
Dispatcher.Invoke
与repos / viewmodels进行交互
不,不要使用Dispatcher.Invoke
与存储库数据库上下文进行交互。与DB async 进行交互。请注意,用户界面图层的Dispatcher.Invoke
仅 。