C# 无法更新Datagrid并将更改保存到数据库

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,一个ViewModel中产品类型的可观察集合,还有一个EventToCommand的实现,如下所示。 我想从“数量和成本的乘积”列更新“总计”列,并保存更改,而不使用隐藏的邪恶代码或Windows窗体DataGridView。 我怎样才能做到这一点? 数据网格:

<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();
        }
    }