Martin Kariuki Martin Kariuki - 1 month ago 8
C# Question

Unable to update Datagrid and save changes to database

I have a datagrid, an ObservableCollection of Product Types in a ViewModel and an implementation of EventToCommand like shown below.
I would like to update the Total Column from the product of Quantity and Cost Column and save the changes without using the evil code behind or Windows Forms DataGridView.
How can I achieve this?
Datagrid:

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



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


Then in the Model:

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


The datagrid is loading products but not updating the Total when Cost and Quantity is changed. Also, not saving the changes in database

Answer Source

The output will be like this:- enter image description here

Change your Xaml like give below

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

And in View Model you Bindings be like

public BindingList<Product> ProductList
{
 get
  {
   return _proxy.ProductList;
  }
}

And EndEdit Command Should execute the following function

private void ExecuteEndEdit(DataGridRowEditEndingEventArgs param)
 {
  var product  = param.Row.Item as Product; 
  var result = ProductList.FirstOrDefault(p => p.Id == product.Id);
  var index= ProductList.IndexOf(result);
  result.Total = result.Cost * result.Quantity;
  ProductList.ResetItem(index);
 }

Your IDataService can Expose Binding List like

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

The Context.Save will save your code.