【问题标题】:Unable to update Datagrid and save changes to database无法更新 Datagrid 并将更改保存到数据库
【发布时间】:2018-01-19 15:59:21
【问题描述】:

我有一个数据网格、一个 ViewModel 中产品类型的 ObservableCollection 和一个 EventToCommand 的实现,如下所示。 我想从 Quantity 和 Cost Column 的乘积中更新 Total Column 并保存更改,而不使用背后的恶意代码或 Windows Forms 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();
    }

然后在模型中:

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

当成本和数量发生变化时,数据网格正在加载产品但不更新总计。另外,不保存数据库中的更改

【问题讨论】:

  • 如果您的模型 Total setter 正在实现 INotifyPropertChanged 接口(未显示),那么我能想到的唯一建议是将 UpdateSourceTrigger=PropertyChanged 添加到您的绑定中。
  • 当 ViewModel 中没有这样的属性时,为什么要将 DataGrid ItemsSource 绑定到名为 ExamsList 的属性?还是您在示例中忘记了此属性?
  • @SebastianRichter 这是一个错字。然而,这不是问题出在哪里
  • @stuicidle 模型来自实体数据模型
  • 你的问题终于解决了。根本不需要编码。查看解决方案

标签: c# wpf mvvm datagrid mvvm-light


【解决方案1】:

要更新DataGrid 中的“总计”列,Product 类应实现INotifyPropertyChanged 接口并为PropertyChanged 属性引发PropertyChanged 事件:

private double _total;
public double Total
{
    get { return _total; }
    set { _total = value; OnPropertyChanged("Total"); }
}

为了能够将值保存到数据库,您需要将 Total 属性映射到数据库表中的列,就像您(希望)对其他列所做的那样。

【讨论】:

  • 首先,我不能绑定到单个属性,因为它是一个项目列表。此外,在 MVVM 方面,Set(ref, _property,value) 实现了 INotifyPropertChanged。
  • 您已经绑定到 DataGridTextColumn 中的单个属性...并且它是 Product 类的 Total 属性的设置器,它应该调用 Set 方法,而不是 MyProduct 属性。
  • 我绑定的这个项目来自一个可观察的项目集合,比如ObservableCollection&lt;Product&gt;,所以当我绑定时,我绑定到集合中的项目的属性,比如Product.Price。我是否需要创建另一个项目,如果需要,如何将数据加载到网格中?我可能从你的回答中遗漏了一些东西。
  • 当您设置 Product 的 Total 属性时,只有当 Product 类实现 INotifyPropertyChanged 接口并在 Total 属性的 setter 中引发 PropertyChanged 事件时,DataGrid 中的总计列才会显示此值。在我的回答中说。 ItemsSource 属性是否绑定到 ObservableCollection 无关紧要。
【解决方案2】:

输出将是这样的:-

更改您的 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>

而在视图模型中,你的绑定就像

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

而 EndEdit 命令应该执行如下函数

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

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

Context.Save 将保存您的代码。

【讨论】:

  • 请根据您的需要进行重构。 :)
  • 谁能解释原因。未经测试将其标记为不作为答案。这是有效的解决方案
  • 让我测试一下代码,我会尽快将其标记为答案,忽略不赞成的人
  • 如何初始化 ProductList 因为ProductList = new new BindingList&lt;Product&gt;();ProductList =context.Products.Local.ToBindingList&lt;Product&gt;(); 似乎不起作用,而foreach (var p in context.Products) { ProductsList.Add(p); } 似乎将每个项目添加了两次并且不保存context.SaveChanges()
  • 不,我没有初始化它。您只需直接使用 context.Products.Local.ToBindingList();无需在 IdataService 中创建它。只需公开来自数据服务的真实集合。它将确保一致性
猜你喜欢
  • 2016-04-09
  • 2012-02-23
  • 1970-01-01
  • 1970-01-01
  • 2013-01-19
  • 2012-06-25
  • 2015-11-11
  • 2020-08-23
  • 1970-01-01
相关资源
最近更新 更多