C# 使用实体框架实现MVVM模式-添加和删除
我试图在我的WPF项目上实现MVVM模式,该项目使用实体框架来获取/操作数据。 我很困惑,我想知道在我的数据库模型对象集合上验证更改应该在哪里??? 我的应用程序如下:在我看来,我有一个人员数据网格,两个文本框将加载所选人员的姓名,一个按钮用于更新行的更改,一个按钮用于删除所选行 在我的ModelView中,我有一个observableCollection,它将在类初始化时加载,其中包含来自数据库(实体)的信息+两个用于添加/删除按钮的RelayCommand(请查找下面的代码) 问题是我没有很好地理解MVVM的原理,在哪里、何时以及如何将对数据的修改推送到数据库? 现在,当我更新数据库中的一行,并保存对可观察集合的DB上下文修改时,我会提交,但当我删除一个项目时,它不是cdase,我必须在数据库中手动查找它并删除它(我已将我的可观察集合附加到一个NotifyCollectionChangedEventHandler事件,该事件将处理该事件)。。。我不明白使用可观察集合的意义 对于使用数据库数据的“完美”mvvm体系结构,有什么简单的解释吗??? 谢谢 我的视图模型C# 使用实体框架实现MVVM模式-添加和删除,c#,wpf,entity-framework,mvvm,C#,Wpf,Entity Framework,Mvvm,我试图在我的WPF项目上实现MVVM模式,该项目使用实体框架来获取/操作数据。 我很困惑,我想知道在我的数据库模型对象集合上验证更改应该在哪里??? 我的应用程序如下:在我看来,我有一个人员数据网格,两个文本框将加载所选人员的姓名,一个按钮用于更新行的更改,一个按钮用于删除所选行 在我的ModelView中,我有一个observableCollection,它将在类初始化时加载,其中包含来自数据库(实体)的信息+两个用于添加/删除按钮的RelayCommand(请查找下面的代码) 问题是我没有很
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows;
using MVVMOK.Models;
using MVVMOK.Base;
using System.Collections.Specialized;
namespace MVVMOK.ViewModel
{
class MainWindowViewModel : ViewModelBase
{
private DW_MargoEntities contexte;
//Constructor
public MainWindowViewModel()
{
contexte = new DATABASEEntities();
collectionOfCollaborators = new ObservableCollection<Collaborator>();
foreach (Collaborator c in contexte.Collaborator)
{
collectionOfCollaborators.Add(c);
}
//Abonnement pour l'ajout ou la suppression d'éléments :
collectionOfCollaborators.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(collectionOfCollaboratorsChanged);
//Assignation des commandes :
this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));
this._updateCommand = new RelayCommand(new Action<object>(UpdateDB));
}
//liste des propriétés publiques:
//Propriété pour représenter l'élément séléctionné du datagrid
private Collaborator selectedItem;
public Collaborator _selectedItem
{
get { return selectedItem; }
set
{
if (value != selectedItem)
{
selectedItem = value;
OnPropertyChanged("_selectedItem");
};
}
}
//Propriété pour représenter l'élément séléctionné:
private ObservableCollection<Collaborator> collectionOfCollaborators;
public ObservableCollection<Collaborator> _collectionOfCollaborators
{
get { return collectionOfCollaborators; }
set
{
this.collectionOfCollaborators = value;
OnPropertyChanged("_collectionOfCollaborators");
}
}
//Commandes :
public ICommand _updateCommand
{
get;
set;
}
public ICommand _deleteComand
{
get;
set;
}
void collectionOfCollaboratorsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Collaborator f = new Collaborator();
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
for(int i = 0; i<e.NewItems.Count;i++)
{
if (e.NewItems[i].GetType().Equals(f.GetType()))
{
contexte.Collaborator.Add(e.NewItems[i] as Collaborator);
}
}
contexte.SaveChanges();
break;
case NotifyCollectionChangedAction.Remove:
for (int i = 0; i < e.OldItems.Count; i++)
{
if (e.OldItems[i].GetType().Equals(f.GetType()))
{
contexte.Collaborator.Remove(e.OldItems[i] as Collaborator);
}
}
contexte.SaveChanges();
break;
//Reset = Clear
}
}
//Services :
public void UpdateDB(object msg)
{
contexte.SaveChanges();
}
public void DeleteRow(object msg)
{
_collectionOfCollaborators.Remove(_selectedItem);
contexte.SaveChanges();
}
}
}
我的XAML
<Window x:Class="MVVMOK.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MVVMOK.ViewModel"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<!-- Declaratively create an instance of our SongViewModel -->
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid Height="237" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479">
<DataGrid AutoGenerateColumns="False" Height="237" HorizontalAlignment="Left" Name="dataGrid1" VerticalAlignment="Top" Width="479" ItemsSource="{Binding Path=_collectionOfCollaborators, Mode=TwoWay}" SelectionMode="Single" SelectedItem="{Binding Path=_selectedItem, Mode=TwoWay}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Id}" Header="ID" />
<DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" Width="4*" />
</DataGrid.Columns>
</DataGrid>
</Grid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="104,255,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Name, Mode=TwoWay}" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="104,283,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text ="{Binding Path=_selectedItem.Surname, Mode=TwoWay}" />
<Label Content="Name" Height="28" HorizontalAlignment="Left" Margin="50,255,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="Surname" Height="28" HorizontalAlignment="Left" Margin="37,283,0,0" Name="label2" VerticalAlignment="Top" />
<Button Content="Delete Row" Height="23" HorizontalAlignment="Left" Margin="416,260,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=_deleteComand}"/>
<Button Content="Update All" Height="23" HorizontalAlignment="Left" Margin="335,260,0,0" Name="button2" VerticalAlignment="Top" Width="75" Command="{Binding Path=_updateCommand}"/>
</Grid>
</Window>
我认为mvvm中没有“THE”方法,它总是有几种方法,这取决于具体情况
但是您的解决方案有一个名为IDataErrorInfo
的接口,它可以帮助您解决问题
以本文为例。。。
或在此:
也许您应该考虑使用存储库模式或简单的DataService
从视图模型中隐藏实体框架
希望这能有所帮助……我认为mvvm中没有“那种”方式——总是有好几种,这要视情况而定
但是您的解决方案有一个名为IDataErrorInfo
的接口,它可以帮助您解决问题
以本文为例。。。
或在此:
也许您应该考虑使用存储库模式或简单的DataService
从视图模型中隐藏实体框架
希望这能有所帮助……我不知道你为什么看不到预期的结果,但我想我会给你一些关于如何更好地构建这个的想法 当数据更改时,您真正想要做的是应用命令。例如,应该应用delete命令。处理此命令时,您可以执行任何验证,并保留更改或标记错误。因此,您在relay命令中包装的DeleteRow类实际上应该是应用程序模型层中的一个单独类。 您可以有一个使用MVVM的web层,但它应该是持久性无关的,它应该应用一个命令,然后在命令成功或失败时做出适当的反应
this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));
this.\u deleteComand=newrelayCommand(新操作(DeleteRow));
可能更像
this._deleteComand = new RelayCommand(new Action<object>() => {new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem = _selectedItem})});
this.\u deleteComand=new RelayCommand(new Action()=>{new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem=\u SelectedItem})});
DeleteCommandHandler和DeleteCommand将构成模型的一部分(我将为此使用不同的类库)
现在,您的处理程序需要了解您的持久性机制,因此您可以在处理程序中创建DW_MargoEntities上下文并执行删除操作
这样做的好处是视图模型不再负责更新模型,因此视图模型将更加简单,并且不会直接依赖于所使用的数据库
一旦你有了一个命令处理程序模式设置,我将转向上下文的依赖注入
例如,不必说new DeleteCommandHandler(),您可以要求一个控制反转容器(如Structure Map)来构建它
ObjectFactory.GetInstance<DeleteCommandHandler>();
ObjectFactory.GetInstance();
然后,您的DeleteCommandHandler类可以如下所示
class DeleteCommandHandler
{
DW_MargoEntities context;
public DeleteCommandHandler(DW_MargoEntities context)
{
this.context = context;
}
public bool Apply(DeleteCOmmand command)
{
if (not valid) {return false;}
var item = context.LoadEntityById<EntityTypeHere>(command.SelectedItem) // Query the item
context.Delete(item);
return true;
}
}
类DeleteCommandHandler
{
边缘实体语境;
公共DeleteCommandHandler(DW_MargoEntities上下文)
{
this.context=上下文;
}
公共布尔应用(删除命令)
{
如果(无效){返回false;}
var item=context.LoadEntityById(command.SelectedItem)//查询该项
删除(项目);
返回true;
}
}
抱歉说得有点含糊,有很多事情要解释,现在已经有点晚了。阅读一下命令模式我不知道你为什么看不到预期的结果,但我想我会给你一些关于如何更好地构建它的想法 当数据更改时,您真正想要做的是应用命令。例如,应该应用delete命令。处理此命令时,您可以执行任何验证,并保留更改或标记错误。因此,您在relay命令中包装的DeleteRow类实际上应该是应用程序模型层中的一个单独类。 您可以有一个使用MVVM的web层,但它应该是持久性无关的,它应该应用一个命令,然后在命令成功或失败时做出适当的反应
this._deleteComand = new RelayCommand(new Action<object>(DeleteRow));
this.\u deleteComand=newrelayCommand(新操作(DeleteRow));
可能更像
this._deleteComand = new RelayCommand(new Action<object>() => {new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem = _selectedItem})});
this.\u deleteComand=new RelayCommand(new Action()=>{new DeleteCommandHandler().Apply(new DeleteCommand(){SelectedItem=\u SelectedItem})});
DeleteCommandHandler和DeleteCommand将构成模型的一部分(我将使用不同的cl)