在ViewModel

时间:2017-03-25 09:10:16

标签: c# wpf mvvm entity-framework-6 dbcontext

我正在使用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();
}

我尝试了两种方法:

  1. 在MainViewModel中设置DispatcherTimer,每隔2秒使用ViewModel.Repository.LoadAll为每个repo更新ViewModel。每隔2秒就会滞后我的UI,但它确实有效。
  2. 将新数据保存到数据库时,还要通过实时将实体添加到存储库。

    Application.Current.Dispatcher.Invoke (     ()=>     {         _clientRepository.Add(客户端);     } );

  3. 这样,实体会立即出现在GUI中,但也有轻微的滞后(移动窗口时),我无法更新现有实体的属性。

    问题是如何重构这一点以允许GUI和后台与实体交互。如何正确组合存储库和MVVM?

2 个答案:

答案 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