在datagridview中引发事件以更新数据库以删除或更新MVVM方法

时间:2013-02-11 05:03:41

标签: wpf entity-framework mvvm datagridview

我认为我遗漏了一些简单但我基本上采用多步法获取数据的方法。让我在一个例子中浏览一个更简单的版本。

  1. 我有一个实现INotifyPropertyChanged的可观察集合
  2. Observable Collection属于'POCO'类,它是一个简单的POCO类,构成了这两个属性:

    PersonID int { get; set; }
    Name string { get; set; }
    
  3. 我有一个实体到sql数据模型,它映射了一个在POCO类中包含相同元值的简单数据库表,让我们说简单的例子它有三个行值:

    PersonID, Name
    1,  Brett
    2,  Emily
    3,  Test
    
  4. 可观察集合在ModelView中连接如下:

    ObservableCollection<POCO> _Pocos;
    POCOEntities ee = new POCOEntities();
    
    public ObservableCollection<POCO> POCOs
    {
        get
        {
            if (_Pocos == null)
            {
                List<POCO> mes = this.GetPOCOs();
                _Pocos= new ObservableCollection<POCO>(mes);
            }
    
            return _Pocos;
        }
        set
        {
            _Pocos = value;
    
            OnPropertyChanged("POCOs");
        }
    }
    
    List<POCO> GetPOCOs()
    {
        return ee.vPOCO.Select(p => new POCOView()
            {
                PersonId = p.PersonID,
                Name = p.Name
            }).ToList();
    }
    
  5. 我也有一个当前项目连线。

    POCO _CurrentPOCO;
    
    public POCO CurrentPOCO
    {
        get { return _CurrentPOCO; }
        set
        {
            _CurrentPOCO = value;
    
            OnPropertyChanged("CurrentPOCO");
        }
    }
    
  6. 4和5是ModelView的内核我将它们连接到datagrid的视图,如下所示:

     <DataGrid x:Name="datagrid" 
          ItemsSource="{Binding POCOs}" 
          CurrentItem="{Binding CurrentPOCO}" />
    
  7. 这是我没有得到的部分,如何近乎实时地更新数据库的实体模型?该集合连接正常并更新,如何告诉数据库发生了什么?如果我设置了像'CellEditEnding'或'SelectionChanged'这样的事件,并尝试从我的实体模型实现更新proc,那么它将在ModelView中实现BOMBS。如果我只坚持它背后的代码,那么有点,但似乎并没有捕获'后'改变的价值。

  8. 即使使用ICommand属性并实现在MVVM中完成的relay命令。这些方法不起作用。所以我很好奇,如果我过度思考它和他们可以烘烤的某种类型的界面,那将为你做清理数据库。我可以处理插入文档,然后使用方法来填充或刷新数据网格,但我希望能够更改datagridview中的值并直接更新数据库。

    内容: 以最简单的方式,我只是想更新数据库,因为我更改了datagridview,并且observablecollection发生了变化,因此两者相互同步。

4 个答案:

答案 0 :(得分:2)

此处有两类更改:

  1. 收集更改,即添加和/或删除项目。要跟踪这些更改,请让您的VM收听ObservableCollection的{​​{1}}事件,并使用CollectionChangedNewItems属性来确定要添加和/或删除的数据来自DB。
  2. 您的某个POCO实例上的属性发生了变化,例如:你改变了一个人的名字。这样的更改不会触发OldItems事件,因为集合本身仍然是相同的。
  3. 对于#2,我将为POCO类实现一个简单的Viewmodel,用于处理其属性的更新。毕竟,您的POCO应被视为业务对象,不应直接暴露给视图。每个PocoVM都包含对单个POCO实例的引用。

    修改

    我添加了或多或少我在我的经验中使用的所有代码,除了存根数据库,因为我不知道你在使用什么以及它是如何工作的。只要它返回项目列表并且您可以告诉它更新单个项目,这并不重要。

    XAML 的 与你的相同,只是我添加了另一个网格(readonly),以便在我的 MysticalDBLayer 接受后显示更改。我也摆脱了CollectionChanged因为我们将使用CurrentItem来跟踪我们正在编辑的项目。

    PocoVM

    查看模型(XAML的DataContext) 这就是这个文件的全部内容。数据库连接可能会根据您使用的内容而有所不同,但基本上我有一个可观察的集合,我以相同的方式填充,除了我为每个POCO 创建一个新的PocoVM(viewmodel)并将新的PocoVM添加到{ {1}}而不是POCO本身

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBlock>Input-Grid</TextBlock>
        <DataGrid Grid.Row="1"
                  ItemsSource="{Binding POCOs}"/>
    
        <TextBlock Grid.Row="2">Readonly-Grid</TextBlock>
        <DataGrid Grid.Row="3"
                  ItemsSource="{Binding POCOs, Mode=OneWay}"
                  IsReadOnly="True"/>
    </Grid>
    

    最后是PocoVM 每当您尝试更新其中一个单元格的值时(只有名称将更新:能够使用此代码作为ObservableCollection只有一个getter),相应的setter将在此类中被调用。在这里,您可以对数据库进行写入,并根据是否成功进行操作。

    class VM
    {
        ObservableCollection<PocoVM> _pocoCollection = new ObservableCollection<PocoVM>();
    
        public ObservableCollection<PocoVM> POCOs
        {
            get
            {
                if (_pocoCollection.Count == 0)
                {
                    _pocoCollection = new ObservableCollection<PocoVM>();
                    IEnumerable<POCO> pocos = MysticalDBLayer.GetItems();
                    foreach (POCO poco in pocos)
                    {
                        _pocoCollection.Add(new PocoVM(poco));
                    }
                }
                return _pocoCollection;
            }
        }
    }
    

答案 1 :(得分:0)

如果我理解正确,您只需要使用 ObservableCollection CollectionChanged 事件。

事件参数包含操作(添加/删除...),您也可以获得 NewItems OldItems

因此,您可以跟踪集合上的更改并与数据库进行同步。 我希望我能帮到你。

答案 2 :(得分:0)

创建自己的ObservableCollection,其覆盖InsertItem()RemoveItem()方法:

public class CustomerCollection : ObservableCollection<Customer>
{
    private DataContext _db;

    public DataContext Db
    {
      get { return _db; }
    }

    public CustomerCollection(IEnumerable<Customer> customers, DataContext context)
      : base(customers)
    {
      _db = context;
    }

    protected override void InsertItem(int index, Customer item)
    {
      this.Db.AddToCustomers(item);
      this.Db.SaveChanges();
      base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
      this.Db.DeleteObject(this[index]);
      this.Db.SaveChanges();
      base.RemoveItem(index);
    }

}

答案 3 :(得分:-1)

这类似于我刚才在这里回答的一个问题WPF datagrid with MVVM。 (因为我是这个网站的新手,我会复制答案)

您应该使用 ListCollectionView

以下是展示如何操作的示例:

1)创建一个名为 ListCollectionViewTest的新WPF项目

2)在MainWindow.xaml.cs中剪切并粘贴以下内容(应该在ViewModel中,但我太懒了)

    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Data;

    namespace ListCollectionViewTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private List<Employee> equivalentOfDatabase = new List<Employee>()
                        {
                            new Employee() { FirstName = "John", LastName = "Doe", IsWorthyOfAttention = true },
                            new Employee() { FirstName = "Jane", LastName = "Doe", IsWorthyOfAttention = true },
                            new Employee() { FirstName = "Mr.", LastName = "Unsignificant", IsWorthyOfAttention = false },
                        };

            public ListCollectionView TestList { get; set; }
            public MainWindow()
            {
                DataContext = this;

                // This is all the magic you need -------
                TestList = new ListCollectionView(equivalentOfDatabase);
                TestList.Filter = x => (x as Employee).IsWorthyOfAttention;

                InitializeComponent();
            }

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show(equivalentOfDatabase.Aggregate("Employees are: \n\r", (acc, emp) => acc + string.Format("    - {0} {1}\n\r", emp.FirstName, emp.LastName), x => x));
            }
        }

        public class Employee
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public bool IsWorthyOfAttention { get; set; }
        }
    }

3)在MainWindow.xaml中剪切并粘贴:

    <Window x:Class="ListCollectionViewTest.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">

        <StackPanel>
            <DataGrid ItemsSource="{Binding TestList}"
                      RowHeight="22"
                      AutoGenerateColumns="True">
            </DataGrid>
            <Button Content="Show All Employees in DB" Click="Button_Click" />
        </StackPanel>        
    </Window>