C# 无法更新Datagrid并将更改保存到数据库
我有一个datagrid,一个ViewModel中产品类型的可观察集合,还有一个EventToCommand的实现,如下所示。 我想从“数量和成本的乘积”列更新“总计”列,并保存更改,而不使用隐藏的邪恶代码或Windows窗体DataGridView。 我怎样才能做到这一点? 数据网格:C# 无法更新Datagrid并将更改保存到数据库,c#,wpf,mvvm,datagrid,mvvm-light,C#,Wpf,Mvvm,Datagrid,Mvvm Light,我有一个datagrid,一个ViewModel中产品类型的可观察集合,还有一个EventToCommand的实现,如下所示。 我想从“数量和成本的乘积”列更新“总计”列,并保存更改,而不使用隐藏的邪恶代码或Windows窗体DataGridView。 我怎样才能做到这一点? 数据网格: <DataGrid x:Name="dataGrid" Margin="5,5,10,5" AutoGenerateColumns="False" HorizontalAlignment="Stretc
<DataGrid x:Name="dataGrid" Margin="5,5,10,5" AutoGenerateColumns="False" HorizontalAlignment="Stretch" ItemsSource="{Binding ProductList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Stretch" Height="566" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="CellEditEnding" SourceObject="{Binding ElementName=Control}">
<cmd:EventToCommand Command="{Binding EndEdit}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Id" Binding="{Binding Path=Id, Mode=TwoWay}" Header="Id"/>
<DataGridTextColumn x:Name="name" Binding="{Binding Path=Name, Mode=TwoWay}" Header="Name"/>
<DataGridTextColumn x:Name="cost" Binding="{Binding Path=Cost, Mode=TwoWay}" Header="Cost"/>
<DataGridTextColumn x:Name="Quantity" Binding="{Binding Path=Quantity, Mode=TwoWay}" Header="Quantity"/>
<DataGridTextColumn x:Name="total" Binding="{Binding Path=Total, Mode=TwoWay}" Header="Total"/>
</DataGrid.Columns>
然后在ViewModel中
private ObservableCollection<Product> _product;
public ObservableCollection<Product> MyProduct
{
get
{
return _product;
}
set
{
Set(ref _product, value);
}
}
public ProductViewModel(IDataService proxy)
{
_proxy = proxy;
LoadCommand = new RelayCommand(DoGetProducts);
EndEdit = new RelayCommand<DataGridCellEditEndingEventArgs>(DoEndEdit);
}
private void DoEndEdit(DataGridCellEditEndingEventArgs obj)
{
DataGridRow row = obj.Row;
Product p = (Product)row.Item;
p.Total = p.Cost*p.Quantity;
_proxy.SaveAll();
}
private observedcollection\u产品;
公共可观测收集MyProduct
{
得到
{
退货产品;
}
设置
{
设置(参考产品、值);
}
}
公共产品视图模型(IDataService代理)
{
_代理=代理;
LoadCommand=新的RelayCommand(DoGetProducts);
EndEdit=新的RelayCommand(DoEndEdit);
}
私有void DoEndEdit(DataGridCellEditEndingEventArgs对象)
{
DataGridRow行=对象行;
产品p=(产品)行.Item;
p、 总计=p.成本*p.数量;
_proxy.SaveAll();
}
然后在模型中:
public class DataService : IDataService
{
ProductEntities context;
public DataService()
{
context = new ProductEntities();
}
public ObservableCollection<Product> GetProducts(){
ObservableCollection<Product> products = new ObservableCollection<Product>();
foreach(var p in context.Products.Tolist()){
products.add(p);
}
return products;
}
public void SaveAll()
{
context.SaveChanges();
}
}
公共类数据服务:IDataService
{
产品实体语境;
公共数据服务()
{
context=newproductentities();
}
公共可观测集合GetProducts(){
ObservableCollection products=新的ObservableCollection();
foreach(context.Products.Tolist()中的var p){
产品.加入(p);;
}
退货产品;
}
公共void SaveAll()
{
SaveChanges();
}
}
当成本和数量发生变化时,datagrid正在加载产品,但不更新总数。另外,Product
类不保存数据库中对DataGrid
中的“total”列的更改以进行更新,Product
类应实现该接口,并引发total
属性的PropertyChanged
事件:
private double _total;
public double Total
{
get { return _total; }
set { _total = value; OnPropertyChanged("Total"); }
}
为了能够将值保存到数据库中,您需要将Total
属性映射到数据库表中的一列,就像您(希望)对其他列所做的那样
输出如下:-
如下面所示更改您的Xaml
<DataGrid x:Name="dataGrid" Margin="5,5,10,5" AutoGenerateColumns="False" HorizontalAlignment="Stretch" ItemsSource="{Binding ProductList}" VerticalAlignment="Stretch" Height="566" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="RowEditEnding" ">
<cmd:EventToCommand Command="{Binding EndEdit}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn x:Name="Id" Binding="{Binding Path=Id, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Header="Id"/>
<DataGridTextColumn x:Name="name" Binding="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Header="Name"/>
<DataGridTextColumn x:Name="cost" Binding="{Binding Path=Cost, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Header="Cost"/>
<DataGridTextColumn x:Name="Quantity" Binding="{Binding Path=Quantity, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Header="Quantity"/>
<DataGridTextColumn x:Name="total" Binding="{Binding Path=Total, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Header="Total"/>
</DataGrid.Columns>
您的IDataService可以公开绑定列表,如
public BindingList<Product> ProductList
{
get
{
return _proxy.ProductList;
}
}
public class DataService : IDataService
{
ProductEntities context;
public DataService()
{
context = new ProductEntities();
}
public BindingList<Product> ProductList
{
get
{
//EDIT: YOU HAVE TO CALL context.Products.Load(); OR IT WILL RETURN EMPTY RESULTS
context.Products.Load();
return context.Products.Local.ToBindingList<Product>();
}
}
public void SaveAll()
{
context.SaveChanges();
}
}
公共类数据服务:IDataService
{
产品实体语境;
公共数据服务()
{
context=newproductentities();
}
公共绑定列表产品列表
{
得到
{
//编辑:必须调用context.Products.Load();否则它将返回空结果
context.Products.Load();
返回context.Products.Local.ToBindingList();
}
}
公共void SaveAll()
{
SaveChanges();
}
}
Context.Save将保存您的代码
首先,我不能绑定到单个属性,因为它是一个项目列表。另外,在MVVM灯光下,
Set(ref,_property,value)
实现了INotifyPropertChanged。您已经绑定到DataGridTextColumn中的单个属性……并且应该调用Set方法的是Product类的Total属性的setter,不是MyProduct属性。我绑定到的此项来自可观察的项集合,如可观察集合
,因此当我绑定时,我绑定到集合中的项的属性,如Product.Price
。我是否需要创建另一个项目?如果需要,数据将如何加载到网格?您的回答中可能缺少某些内容。当您设置Product的Total属性时,只有当Product类实现INotifyPropertyChanged接口并在Total属性的setter中引发PropertyChanged事件时,DataGrid中的Total列才会显示此值,如我在回答中所述。ItemsSource属性是否绑定到ObservableCollection并不重要。如果您的models Total setter正在实现INotifyPropertChanged接口(未显示此接口)那么我能想到的唯一建议就是添加UpdateSourceTrigger=PropertyChanged到您的绑定中。当ViewModel中没有这样的属性时,为什么要将您的DataGrid
ItemsSource
绑定到名为ExamList
的属性中?或者你在你的例子中忘记了这个属性?@SebastianRichter,这是一个打字错误。然而,问题不在这里from@stuicidle该模型来自实体数据模型您的问题最终得到解决。根本不需要编码。参见解决方案请根据您的需要进行重构。:)谁能解释一下原因吗。未经测试,它不会被标记为答案。这是有效的解决方案让我测试代码,我会尽快将其标记为答案忽略downvotershow是否初始化ProductList,因为ProductList=new-BindingList()
和ProductList=context.Products.Local.ToBindingList()当foreach(context.Products中的var p){ProductsList.Add(p);}
似乎将每个项添加两次,并且不在context.SaveChanges()上保存时,code>似乎不起作用。
否我不初始化它。您只需直接获取context.Products.Local.ToBindingList();无需在IdataService中创建它。只需公开来自数据服务的真实集合。它将确保一致性
public class DataService : IDataService
{
ProductEntities context;
public DataService()
{
context = new ProductEntities();
}
public BindingList<Product> ProductList
{
get
{
//EDIT: YOU HAVE TO CALL context.Products.Load(); OR IT WILL RETURN EMPTY RESULTS
context.Products.Load();
return context.Products.Local.ToBindingList<Product>();
}
}
public void SaveAll()
{
context.SaveChanges();
}
}