WPF DataGrid使用MVVM添加、更新和删除。

时间:2022-04-22 20:14:46

I am looking for a sample code/Article which would demonstrate WPF DataGrid in action with MVVM pattern to add, updated and delete record from database.

我正在寻找一个示例代码/文章,它将使用MVVM模式演示WPF DataGrid如何从数据库中添加、更新和删除记录。

I have a specific requirement for allowing user to insert new record using DataGrid not a new child form.

我有一个特定的要求,允许用户使用DataGrid而不是新的子窗体插入新记录。

If anyone can recommend good resource or provide a sample for that particular task it would be great help for me.

如果有人能推荐好的资源或者提供一个特定任务的样本,这对我将是很大的帮助。

3 个解决方案

#1


2  

Here on CodeProject is an article about WPF DataGrid + MVVM pattern:

在CodeProject上有一篇关于WPF DataGrid + MVVM模式的文章:

http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx

http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx

#2


1  

I don't know of any good articles on the subject, but I don't see the problem; as long as you bind to an ObservableCollection or ListCollectionView containing objects whose class has a default constructor (I don't think there are other restrictions), the DataGrid will handle things pretty well. The collection you bind to must have some way of adding new items, which is why you need to bind to an ICollection or IEditableCollectionView - the latter is preferred, as it has specific options for controlling the creation of items - see AddNew, CanAddNew etc, which the DataGrid works well with.

我不知道关于这个话题有什么好的文章,但我不认为有什么问题;只要绑定到包含其类具有默认构造函数的对象的ObservableCollection或ListCollectionView(我认为没有其他限制),DataGrid就能很好地处理事情。收集你绑定必须有一些方法添加新项目,这就是为什么你需要绑定到一个ICollection或IEditableCollectionView——后者是首选,因为它有特定的选项控制项的创建——看到AddNew CanAddNew等等,DataGrid行之有效。

#3


1  

Edit:Pasted the part, which fits your question. Full article: http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples

编辑:粘贴部分,适合您的问题。全文:http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples

This example demonstrates how to use a DataGrid to perform CRUD operations via binding where the database integration is decoupled via a Data Access Layer (DAL).

这个例子演示了如何使用DataGrid通过绑定来执行CRUD操作,通过数据访问层(DAL)解耦数据库集成。

The Architecture

该体系结构

This example is a simple CRUD application which allows the user to edit items in the Customers table of the Northwind database. The example has a Data Access Layer, which exposes Find/ Delete/Update methods that operate on simple data objects, and a Presentation Layer that adapts these objects in such a way that they can be bound effectively by the WPF Framework. Because we are only performing CRUD functions, I have not added a Business Logic Layer (BLL); if you are a purist, you could add a pass-through BLL; however, I feel it would add little to this example.

这个示例是一个简单的CRUD应用程序,允许用户在Northwind数据库的Customers表中编辑条目。该示例具有一个数据访问层,该层公开在简单数据对象上操作的Find/ Delete/Update方法,以及一个表示层,该表示层对这些对象进行调整,使它们能够被WPF框架有效地绑定。因为我们只执行CRUD函数,所以没有添加业务逻辑层(BLL);如果你是一个纯粹主义者,你可以添加一个传递BLL;然而,我觉得这对这个例子没什么帮助。

The key classes within this architecture are shown below:

该体系结构中的关键类如下所示:

The Data Access Layer exposes an interface for managing the lifecycle of the Customer Data Objects. The class which implements this interface uses a typed DataSet as a database integration layer; however, this is hidden from the clients of the DAL. The presence of this layer means that we are not directly coupled to the database schema or the generated dataset schema, i.e., we can change our schema, yet still provide the interface given below to our clients:

数据访问层公开了管理客户数据对象生命周期的接口。实现此接口的类使用类型化数据集作为数据库集成层;但是,这对DAL客户来说是隐藏的。这个层的存在意味着我们不直接耦合到数据库模式或生成的数据集模式,例如。,我们可以更改我们的模式,但仍会向客户提供以下界面:

public interface ICustomerDataAccessLayer
{
    /// Return all the persistent customers
    List<CustomerDataObject> GetCustomers();

    /// Updates or adds the given customer
    void UpdateCustomer(CustomerDataObject customer);

    /// Delete the given customer
    void DeleteCustomer(CustomerDataObject customer);
}
public class CustomerDataObject
{
    public string ID { get; set; }

    public string CompanyName { get; set; }

    public string ContactName { get; set; }
}

As you can see, there are no UI framework specific interfaces or classes (such as ObservableCollection) exposed by the DAL. The problem here is how to bind the customers returned by ICustomerDataAccess.GetCustomers to our DataGrid and ensure that changes are synchronised with the database.

如您所见,不存在由DAL公开的特定于UI框架的接口或类(如ObservableCollection)。这里的问题是如何绑定ICustomerDataAccess返回的客户。GetCustomers到我们的DataGrid,并确保更改与数据库同步。

We could bind the DataGrid directly to our customer collection, List; however, we need to ensure that the UpdateCustomer and DeleteCustomer methods on our DAL interface are invoked at the appropriate points in time. One approach that we might take is to handle the events / commands exposed by the DataGrid in order to determine what action it has just performed or intends to perform on the bound customer collection. However, in doing so, we would be writing integration code that is specific to the DataGrid. What if we wanted to change the UI to present a ListView and a number of TextBoxes (details view)? We would have to re-write this logic. Also, none of the DataGrid events quite fit what we want. There are "Ending" events, but no "Ended" events; therefore, the data visible to event handlers is not in its committed state. A better approach would be if we could adapt our collection of Customer objects in such a way that they could be bound to any suitable WPF UI control, with add/edit/remove operations synchronised with the database via our DAL. Handling Delete Operations

我们可以将DataGrid直接绑定到我们的客户集合列表;但是,我们需要确保在适当的时间点调用DAL接口上的UpdateCustomer和DeleteCustomer方法。我们可能采取的一种方法是处理DataGrid公开的事件/命令,以确定它刚刚执行了什么操作或打算在绑定的客户集合上执行什么操作。但是,在这样做时,我们将编写特定于DataGrid的集成代码。如果我们想要更改UI以显示一个ListView和一些文本框(详情视图),该怎么办?我们必须重写这个逻辑。而且,没有一个DataGrid事件非常符合我们的需求。有“结束”事件,但没有“结束”事件;因此,事件处理程序可见的数据不在提交状态。更好的方法是,如果我们能够调整我们的客户对象集合,使它们能够绑定到任何合适的WPF UI控件,并通过我们的DAL与数据库同步添加/编辑/删除操作。处理删除操作

The ObservableCollection class is a good candidate for our data binding needs. It exposes a CollectionChanged event which is fired whenever items are added or removed from the collection. If we copy our customer data into an ObservableCollection and bind this to the DataGrid, we can handle the CollectionChanged event and perform the required operation on the DAL. The following code snippet shows how the CustomerObjectDataProvider (which is defined as an ObjectDataProvider in the XAML) constructs an ObservableCollection of CustomerUIObjects. These UI objects simply wrap their data object counterparts in order to expose the same properties.

ObservableCollection类很适合我们的数据绑定需求。它公开一个集合更改事件,该事件在添加或从集合中删除项目时触发。如果我们将客户数据复制到一个ObservableCollection中并将其绑定到DataGrid中,那么我们就可以处理CollectionChanged事件并在DAL上执行所需的操作。下面的代码片段显示了CustomerObjectDataProvider(在XAML中定义为ObjectDataProvider)如何构造customeruiobject的观察汇总。这些UI对象简单地包装它们的数据对象副本,以便公开相同的属性。

public CustomerObjectDataProvider()
{
    dataAccessLayer = new CustomerDataAccessLayer();
}

public CustomerUIObjects GetCustomers()
{
    // populate our list of customers from the data access layer
    CustomerUIObjects customers = new CustomerUIObjects();

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers();
    foreach (CustomerDataObject customerDataObject in customerDataObjects)
    {
        // create a business object from each data object
        customers.Add(new CustomerUIObject(customerDataObject));
    }

    customers.CollectionChanged += new
      NotifyCollectionChangedEventHandler(CustomersCollectionChanged);

    return customers;
}

void CustomersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Remove)
    {
        foreach (object item in e.OldItems)
        {
            CustomerUIObject customerObject = item as CustomerUIObject;

            // use the data access layer to delete the wrapped data object
            dataAccessLayer.DeleteCustomer(customerObject.GetDataObject());
        }
    }
}

When a user deletes a row with the DataGrid control, the CollectionChanged event is fired on the bound collection. In the event handler, we invoke the DAL DeleteCustomer method with the wrapped data object passed as the parameter.

当用户使用DataGrid控件删除一行时,集合更改事件将在绑定集合上触发。在事件处理程序中,我们使用作为参数传递的包装数据对象调用DAL DeleteCustomer方法。

Handling delete operations is relatively straightforward, but how about updates or insertions? You might think that the same approach can be used, the NotifyCollectionChangedEventArgs.Action property does include Add operations; however, this event is not fired when the items within the collection are updated. Furthermore, when a user adds a new item to the DataGrid, the object is initially added to the bound collection in a non-initialized state, so we would only ever see the object with its default property values. What we really need to do is determine when the user finishes editing an item in the grid. Handling Updates / Inserts

处理删除操作相对简单,但是更新或插入呢?您可能认为可以使用相同的方法,NotifyCollectionChangedEventArgs。动作属性包括添加操作;但是,在更新集合中的项时不会触发此事件。此外,当用户向DataGrid添加一个新项时,该对象首先被添加到非初始化状态的绑定集合中,因此我们只会看到具有默认属性值的对象。我们真正需要做的是确定用户何时完成对网格中的项目的编辑。处理更新/插入

To determine when a user finishes editing a bound item, we need to delve a little deeper into the binding mechanism itself. The DataGrid is able to perform an atomic commit of the row which is currently being edited; this is made possible if the bound items implement the IEditableObject interface which exposes BeginEdit, EndEdit, and CancelEdit methods. Typically, an object implementing this interface would return to its state at the point when the BeginEdit method was called as a response to the CancelEdit method being invoked. However, in this instance, we are not really concerned about being able to cancel edits; all we really need to know is when the user has finished editing a row. This is indicted when the DataGrid invokes EndEdit on our bound item.

要确定用户何时完成编辑绑定项,我们需要深入研究绑定机制本身。DataGrid能够执行当前正在编辑的行的原子提交;如果绑定项实现了IEditableObject接口,它公开了BeginEdit、EndEdit和CancelEdit方法,这就成为可能。通常,实现这个接口的对象会在调用BeginEdit方法作为调用CancelEdit方法的响应时返回到它的状态。但是,在此实例中,我们并不真正关心是否能够取消编辑;我们真正需要知道的是用户何时完成了对一行的编辑。当DataGrid在我们的绑定项上调用EndEdit时,这就被起诉了。

In order to notify the CustomerDataObjectProvider that EndEdit has been invoked on one of the objects in the bound collection, the CustomerUIObject implements IEditableObject as follows:

为了通知在绑定集合中的一个对象上调用了EndEdit的CustomerDataObjectProvider, CustomerUIObject实现IEditableObject如下:

public delegate void ItemEndEditEventHandler(IEditableObject sender);

public event ItemEndEditEventHandler ItemEndEdit;

#region IEditableObject Members

public void BeginEdit() {}

public void CancelEdit() {}

public void EndEdit()
{
    if (ItemEndEdit != null)
    {
        ItemEndEdit(this);
    }
}

#endregion

When items are added to the CustomerUIObjects collection, this event is handled for all the items in the collection, with the handler simply forwarding the event:

当向CustomerUIObjects集合添加项时,此事件将针对集合中的所有项进行处理,处理程序只需转发事件:

public class CustomerUIObjects : ObservableCollection<CustomerDataObject>
{
    protected override void InsertItem(int index, CustomerUIObject item)
    {
        base.InsertItem(index, item);

        // handle any EndEdit events relating to this item
        item.ItemEndEdit += new ItemEndEditEventHandler(ItemEndEditHandler);
    }

    void ItemEndEditHandler(IEditableObject sender)
    {
        // simply forward any EndEdit events
        if (ItemEndEdit != null)
        {
            ItemEndEdit(sender);
        }
    }

    public event ItemEndEditEventHandler ItemEndEdit;
}

The CustomerObjectDataProvider can now handle this event to receive the notification of CommitEdit being invoked on any of the bound items. It can then invoke the DAL methods to synchronise the database state:

CustomerObjectDataProvider现在可以处理这个事件来接收在任何绑定项上调用的CommitEdit的通知。然后它可以调用DAL方法来同步数据库状态:

public CustomerUIObjects GetCustomers()
{
    // populate our list of customers from the data access layer
    CustomerUIObjects customers = new CustomerUIObjects();

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers();
    foreach (CustomerDataObject customerDataObject in customerDataObjects)
    {
        // create a business object from each data object
        customers.Add(new CustomerUIObject(customerDataObject));
    }

    customers.ItemEndEdit += new ItemEndEditEventHandler(CustomersItemEndEdit);
    customers.CollectionChanged += new
      NotifyCollectionChangedEventHandler(CustomersCollectionChanged);

    return customers;
}

void CustomersItemEndEdit(IEditableObject sender)
{
    CustomerUIObject customerObject = sender as CustomerUIObject;

    // use the data access layer to update the wrapped data object
    dataAccessLayer.UpdateCustomer(customerObject.GetDataObject());
}

The above code will handle both insert and update operations.

上面的代码将处理插入和更新操作。

In conclusion, this method adapts the data items and collection provided by the DAL into UI items and collections which are more appropriate for data binding within the WPF Framework. All database synchronisation logic is performed by handling event from this bound collection; therefore, there is no WPF DataGrid specific code.

综上所述,该方法将DAL提供的数据项和收集调整为更适合在WPF框架内进行数据绑定的UI项和集合。通过处理来自这个绑定集合的事件来执行所有数据库同步逻辑;因此,没有特定于WPF的数据网格代码。

#1


2  

Here on CodeProject is an article about WPF DataGrid + MVVM pattern:

在CodeProject上有一篇关于WPF DataGrid + MVVM模式的文章:

http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx

http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx

#2


1  

I don't know of any good articles on the subject, but I don't see the problem; as long as you bind to an ObservableCollection or ListCollectionView containing objects whose class has a default constructor (I don't think there are other restrictions), the DataGrid will handle things pretty well. The collection you bind to must have some way of adding new items, which is why you need to bind to an ICollection or IEditableCollectionView - the latter is preferred, as it has specific options for controlling the creation of items - see AddNew, CanAddNew etc, which the DataGrid works well with.

我不知道关于这个话题有什么好的文章,但我不认为有什么问题;只要绑定到包含其类具有默认构造函数的对象的ObservableCollection或ListCollectionView(我认为没有其他限制),DataGrid就能很好地处理事情。收集你绑定必须有一些方法添加新项目,这就是为什么你需要绑定到一个ICollection或IEditableCollectionView——后者是首选,因为它有特定的选项控制项的创建——看到AddNew CanAddNew等等,DataGrid行之有效。

#3


1  

Edit:Pasted the part, which fits your question. Full article: http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples

编辑:粘贴部分,适合您的问题。全文:http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples

This example demonstrates how to use a DataGrid to perform CRUD operations via binding where the database integration is decoupled via a Data Access Layer (DAL).

这个例子演示了如何使用DataGrid通过绑定来执行CRUD操作,通过数据访问层(DAL)解耦数据库集成。

The Architecture

该体系结构

This example is a simple CRUD application which allows the user to edit items in the Customers table of the Northwind database. The example has a Data Access Layer, which exposes Find/ Delete/Update methods that operate on simple data objects, and a Presentation Layer that adapts these objects in such a way that they can be bound effectively by the WPF Framework. Because we are only performing CRUD functions, I have not added a Business Logic Layer (BLL); if you are a purist, you could add a pass-through BLL; however, I feel it would add little to this example.

这个示例是一个简单的CRUD应用程序,允许用户在Northwind数据库的Customers表中编辑条目。该示例具有一个数据访问层,该层公开在简单数据对象上操作的Find/ Delete/Update方法,以及一个表示层,该表示层对这些对象进行调整,使它们能够被WPF框架有效地绑定。因为我们只执行CRUD函数,所以没有添加业务逻辑层(BLL);如果你是一个纯粹主义者,你可以添加一个传递BLL;然而,我觉得这对这个例子没什么帮助。

The key classes within this architecture are shown below:

该体系结构中的关键类如下所示:

The Data Access Layer exposes an interface for managing the lifecycle of the Customer Data Objects. The class which implements this interface uses a typed DataSet as a database integration layer; however, this is hidden from the clients of the DAL. The presence of this layer means that we are not directly coupled to the database schema or the generated dataset schema, i.e., we can change our schema, yet still provide the interface given below to our clients:

数据访问层公开了管理客户数据对象生命周期的接口。实现此接口的类使用类型化数据集作为数据库集成层;但是,这对DAL客户来说是隐藏的。这个层的存在意味着我们不直接耦合到数据库模式或生成的数据集模式,例如。,我们可以更改我们的模式,但仍会向客户提供以下界面:

public interface ICustomerDataAccessLayer
{
    /// Return all the persistent customers
    List<CustomerDataObject> GetCustomers();

    /// Updates or adds the given customer
    void UpdateCustomer(CustomerDataObject customer);

    /// Delete the given customer
    void DeleteCustomer(CustomerDataObject customer);
}
public class CustomerDataObject
{
    public string ID { get; set; }

    public string CompanyName { get; set; }

    public string ContactName { get; set; }
}

As you can see, there are no UI framework specific interfaces or classes (such as ObservableCollection) exposed by the DAL. The problem here is how to bind the customers returned by ICustomerDataAccess.GetCustomers to our DataGrid and ensure that changes are synchronised with the database.

如您所见,不存在由DAL公开的特定于UI框架的接口或类(如ObservableCollection)。这里的问题是如何绑定ICustomerDataAccess返回的客户。GetCustomers到我们的DataGrid,并确保更改与数据库同步。

We could bind the DataGrid directly to our customer collection, List; however, we need to ensure that the UpdateCustomer and DeleteCustomer methods on our DAL interface are invoked at the appropriate points in time. One approach that we might take is to handle the events / commands exposed by the DataGrid in order to determine what action it has just performed or intends to perform on the bound customer collection. However, in doing so, we would be writing integration code that is specific to the DataGrid. What if we wanted to change the UI to present a ListView and a number of TextBoxes (details view)? We would have to re-write this logic. Also, none of the DataGrid events quite fit what we want. There are "Ending" events, but no "Ended" events; therefore, the data visible to event handlers is not in its committed state. A better approach would be if we could adapt our collection of Customer objects in such a way that they could be bound to any suitable WPF UI control, with add/edit/remove operations synchronised with the database via our DAL. Handling Delete Operations

我们可以将DataGrid直接绑定到我们的客户集合列表;但是,我们需要确保在适当的时间点调用DAL接口上的UpdateCustomer和DeleteCustomer方法。我们可能采取的一种方法是处理DataGrid公开的事件/命令,以确定它刚刚执行了什么操作或打算在绑定的客户集合上执行什么操作。但是,在这样做时,我们将编写特定于DataGrid的集成代码。如果我们想要更改UI以显示一个ListView和一些文本框(详情视图),该怎么办?我们必须重写这个逻辑。而且,没有一个DataGrid事件非常符合我们的需求。有“结束”事件,但没有“结束”事件;因此,事件处理程序可见的数据不在提交状态。更好的方法是,如果我们能够调整我们的客户对象集合,使它们能够绑定到任何合适的WPF UI控件,并通过我们的DAL与数据库同步添加/编辑/删除操作。处理删除操作

The ObservableCollection class is a good candidate for our data binding needs. It exposes a CollectionChanged event which is fired whenever items are added or removed from the collection. If we copy our customer data into an ObservableCollection and bind this to the DataGrid, we can handle the CollectionChanged event and perform the required operation on the DAL. The following code snippet shows how the CustomerObjectDataProvider (which is defined as an ObjectDataProvider in the XAML) constructs an ObservableCollection of CustomerUIObjects. These UI objects simply wrap their data object counterparts in order to expose the same properties.

ObservableCollection类很适合我们的数据绑定需求。它公开一个集合更改事件,该事件在添加或从集合中删除项目时触发。如果我们将客户数据复制到一个ObservableCollection中并将其绑定到DataGrid中,那么我们就可以处理CollectionChanged事件并在DAL上执行所需的操作。下面的代码片段显示了CustomerObjectDataProvider(在XAML中定义为ObjectDataProvider)如何构造customeruiobject的观察汇总。这些UI对象简单地包装它们的数据对象副本,以便公开相同的属性。

public CustomerObjectDataProvider()
{
    dataAccessLayer = new CustomerDataAccessLayer();
}

public CustomerUIObjects GetCustomers()
{
    // populate our list of customers from the data access layer
    CustomerUIObjects customers = new CustomerUIObjects();

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers();
    foreach (CustomerDataObject customerDataObject in customerDataObjects)
    {
        // create a business object from each data object
        customers.Add(new CustomerUIObject(customerDataObject));
    }

    customers.CollectionChanged += new
      NotifyCollectionChangedEventHandler(CustomersCollectionChanged);

    return customers;
}

void CustomersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.Action == NotifyCollectionChangedAction.Remove)
    {
        foreach (object item in e.OldItems)
        {
            CustomerUIObject customerObject = item as CustomerUIObject;

            // use the data access layer to delete the wrapped data object
            dataAccessLayer.DeleteCustomer(customerObject.GetDataObject());
        }
    }
}

When a user deletes a row with the DataGrid control, the CollectionChanged event is fired on the bound collection. In the event handler, we invoke the DAL DeleteCustomer method with the wrapped data object passed as the parameter.

当用户使用DataGrid控件删除一行时,集合更改事件将在绑定集合上触发。在事件处理程序中,我们使用作为参数传递的包装数据对象调用DAL DeleteCustomer方法。

Handling delete operations is relatively straightforward, but how about updates or insertions? You might think that the same approach can be used, the NotifyCollectionChangedEventArgs.Action property does include Add operations; however, this event is not fired when the items within the collection are updated. Furthermore, when a user adds a new item to the DataGrid, the object is initially added to the bound collection in a non-initialized state, so we would only ever see the object with its default property values. What we really need to do is determine when the user finishes editing an item in the grid. Handling Updates / Inserts

处理删除操作相对简单,但是更新或插入呢?您可能认为可以使用相同的方法,NotifyCollectionChangedEventArgs。动作属性包括添加操作;但是,在更新集合中的项时不会触发此事件。此外,当用户向DataGrid添加一个新项时,该对象首先被添加到非初始化状态的绑定集合中,因此我们只会看到具有默认属性值的对象。我们真正需要做的是确定用户何时完成对网格中的项目的编辑。处理更新/插入

To determine when a user finishes editing a bound item, we need to delve a little deeper into the binding mechanism itself. The DataGrid is able to perform an atomic commit of the row which is currently being edited; this is made possible if the bound items implement the IEditableObject interface which exposes BeginEdit, EndEdit, and CancelEdit methods. Typically, an object implementing this interface would return to its state at the point when the BeginEdit method was called as a response to the CancelEdit method being invoked. However, in this instance, we are not really concerned about being able to cancel edits; all we really need to know is when the user has finished editing a row. This is indicted when the DataGrid invokes EndEdit on our bound item.

要确定用户何时完成编辑绑定项,我们需要深入研究绑定机制本身。DataGrid能够执行当前正在编辑的行的原子提交;如果绑定项实现了IEditableObject接口,它公开了BeginEdit、EndEdit和CancelEdit方法,这就成为可能。通常,实现这个接口的对象会在调用BeginEdit方法作为调用CancelEdit方法的响应时返回到它的状态。但是,在此实例中,我们并不真正关心是否能够取消编辑;我们真正需要知道的是用户何时完成了对一行的编辑。当DataGrid在我们的绑定项上调用EndEdit时,这就被起诉了。

In order to notify the CustomerDataObjectProvider that EndEdit has been invoked on one of the objects in the bound collection, the CustomerUIObject implements IEditableObject as follows:

为了通知在绑定集合中的一个对象上调用了EndEdit的CustomerDataObjectProvider, CustomerUIObject实现IEditableObject如下:

public delegate void ItemEndEditEventHandler(IEditableObject sender);

public event ItemEndEditEventHandler ItemEndEdit;

#region IEditableObject Members

public void BeginEdit() {}

public void CancelEdit() {}

public void EndEdit()
{
    if (ItemEndEdit != null)
    {
        ItemEndEdit(this);
    }
}

#endregion

When items are added to the CustomerUIObjects collection, this event is handled for all the items in the collection, with the handler simply forwarding the event:

当向CustomerUIObjects集合添加项时,此事件将针对集合中的所有项进行处理,处理程序只需转发事件:

public class CustomerUIObjects : ObservableCollection<CustomerDataObject>
{
    protected override void InsertItem(int index, CustomerUIObject item)
    {
        base.InsertItem(index, item);

        // handle any EndEdit events relating to this item
        item.ItemEndEdit += new ItemEndEditEventHandler(ItemEndEditHandler);
    }

    void ItemEndEditHandler(IEditableObject sender)
    {
        // simply forward any EndEdit events
        if (ItemEndEdit != null)
        {
            ItemEndEdit(sender);
        }
    }

    public event ItemEndEditEventHandler ItemEndEdit;
}

The CustomerObjectDataProvider can now handle this event to receive the notification of CommitEdit being invoked on any of the bound items. It can then invoke the DAL methods to synchronise the database state:

CustomerObjectDataProvider现在可以处理这个事件来接收在任何绑定项上调用的CommitEdit的通知。然后它可以调用DAL方法来同步数据库状态:

public CustomerUIObjects GetCustomers()
{
    // populate our list of customers from the data access layer
    CustomerUIObjects customers = new CustomerUIObjects();

    List<CustomerDataObject> customerDataObjects = dataAccessLayer.GetCustomers();
    foreach (CustomerDataObject customerDataObject in customerDataObjects)
    {
        // create a business object from each data object
        customers.Add(new CustomerUIObject(customerDataObject));
    }

    customers.ItemEndEdit += new ItemEndEditEventHandler(CustomersItemEndEdit);
    customers.CollectionChanged += new
      NotifyCollectionChangedEventHandler(CustomersCollectionChanged);

    return customers;
}

void CustomersItemEndEdit(IEditableObject sender)
{
    CustomerUIObject customerObject = sender as CustomerUIObject;

    // use the data access layer to update the wrapped data object
    dataAccessLayer.UpdateCustomer(customerObject.GetDataObject());
}

The above code will handle both insert and update operations.

上面的代码将处理插入和更新操作。

In conclusion, this method adapts the data items and collection provided by the DAL into UI items and collections which are more appropriate for data binding within the WPF Framework. All database synchronisation logic is performed by handling event from this bound collection; therefore, there is no WPF DataGrid specific code.

综上所述,该方法将DAL提供的数据项和收集调整为更适合在WPF框架内进行数据绑定的UI项和集合。通过处理来自这个绑定集合的事件来执行所有数据库同步逻辑;因此,没有特定于WPF的数据网格代码。