我在MVVM模式中使用WPF . 我正在使用实体框架 . 我有一个带有选项卡控件的主窗口(Entitlements视图) . 此视图中的选项卡项目均绑定到用户控件的视图 .
权利观点:
<TabControl Grid.Row="1">
<TabItem Header="Accounts" Content="{Binding AccountsViewModel}"/>
<TabItem Header="Users" Content="{Binding UsersViewModel}"/>
</TabControl>
App.Xaml.cs在初始化时实例化Entitlements视图:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainWindow = new MainWindow();
var viewModel = new EntitlementsViewModel();
mainWindow.DataContext = viewModel;
mainWindow.Show();
}
}
DataContext在View Xaml中设置:
xmlns:vm="clr-namespace:DIEntitlements.ViewModels">
<UserControl.Resources>
<vm:AccountsViewModel x:Key="AccountsViewModel"/>
</UserControl.Resources>
<Grid DataContext="{StaticResource AccountsViewModel}">
App.Xaml中的ViewModel DataTemplates:
<ResourceDictionary>
<DataTemplate DataType="{x:Type vm:AccountsViewModel}">
<v:AccountsView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:UsersViewModel}">
<v:UsersView/>
</DataTemplate>
</ResourceDictionary>
最后是一些ViewModel代码:
属性:
private ObservableCollection<tbUsername> _usersCollection;
public ObservableCollection<tbUsername> UsersCollection
{
get { return _usersCollection; }
set
{
_usersCollection = value;
OnPropertyChanged("UsersCollection");
}
}
Linq方法:
private void GetUserHeaders()
{
var query = from u in _context.tbUsernames
where u.accountId == SelectedAccountHeader.accountid
select u;
UsersCollection = new ObservableCollection<tbUsername>(query);
}
在第一个选项卡选择时,将调用相应的ViewModel构造函数,并按预期显示UI . 当更改持久保存回数据库但UI未刷新时,会出现此问题 . 我正在View Models中正确实现INotifyPropertyChanged . 我认为这个问题源于只有视图模型和视图的1个实例在初始化时构造,然后保存在内存中并且在持久化时不重新初始化 . 有没有一种方法可以刷新UI而不需要在UI中使用笨重的“刷新”按钮?
2 回答
继续注释 - 看起来你正在使用ObservableCollection,但是该集合中的对象没有实现INotifyPropertyChanged,因为它们直接来自数据库 .
我建议您需要另一个图层,将这些'POCO'对象转换为实现INotifyPropertyChanged的类 . 你可以从BindableBase继承 . 要使用它创建属性,属性将如下所示:
如果您无法进行所有转换,则可以使用AutoMapper进行转移 .
所以一般的流程是:
获取正在进行的数据
将其转换为在类中的每个属性上实现INotifyPropertyChanged的类 .
添加到ObservableCollection
绑定,因为您目前正在绑定
...然后反过来回到DB的方式 .
我经过多次修补后解决了这个问题 .
这是我的RefreshEntities()方法,它调用MergeOption.OverwriteChanges;它基本上覆盖了上下文实体,并使用来自DB的新数据重新加载集合 . 你告诉EF要覆盖你传入的实体 . 我正在调用这个方法,只要我坚持改变那个视图
看起来非常冗长,但效果很好 . 我建议您在任何MVVM WPF应用程序中尝试更新UI中的视图,该视图已通过用户与EF框架模型中的关联表的交互而发生更改 . 基本上,表和视图之间存在交叉关系,您需要在UI中更新该视图 .
MergeOption.OverwriteChanges会覆盖所有挂起的更改,但您可以使用MergeOption.PreserveChanges将重新加载的值合并到您编辑的值中 .