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

时间:2010-09-06 06:52:51

标签: wpf mvvm datagrid

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

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

如果有人可以推荐好资源或为该特定任务提供样本,那对我来说将是非常有帮助的。

3 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

我不知道有关这个问题的任何好文章,但我没有看到问题;只要绑定到包含其类具有默认构造函数的对象的ObservableCollection或ListCollectionView(我认为没有其他限制),DataGrid就会很好地处理事情。您绑定的集合必须具有添加新项的某种方式,这就是您需要绑定到ICollection或IEditableCollectionView的原因 - 后者是首选,因为它具有控制项创建的特定选项 - 请参阅AddNewCanAddNew等,DataGrid可以很好地使用它。

答案 2 :(得分:1)

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

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

架构

此示例是一个简单的CRUD应用程序,它允许用户编辑Northwind数据库的Customers表中的项目。该示例有一个数据访问层,它公开了对简单数据对象进行操作的查找/删除/更新方法,以及一个表示层,它以这样的方式调整这些对象,使它们可以被WPF框架有效地绑定。因为我们只执行CRUD功能,所以我没有添加业务逻辑层(BLL);如果你是一个纯粹主义者,你可以添加一个传递BLL;但是,我觉得这会给这个例子增添不多。

此架构中的关键类如下所示:

数据访问层公开了一个用于管理客户数据对象生命周期的界面。实现此接口的类使用类型化DataSet作为数据库集成层;但是,这对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; }
}

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

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

ObservableCollection类是我们数据绑定需求的理想选择。它公开了一个CollectionChanged事件,只要在集合中添加或删除项目就会触发该事件。如果我们将客户数据复制到ObservableCollection并将其绑定到DataGrid,我们可以处理CollectionChanged事件并在DAL上执行所需的操作。以下代码片段显示了CustomerObjectDataProvider(在XAML中定义为ObjectDataProvider)如何构造CustomerUIObjects的ObservableCollection。这些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());
        }
    }
}

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

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

要确定用户何时完成对绑定项的编辑,我们需要深入研究绑定机制本身。 DataGrid能够执行当前正在编辑的行的原子提交;如果绑定的项实现IEditableObject接口,该接口公开BeginEdit,EndEdit和CancelEdit方法,则可以实现这一点。通常,实现此接口的对象将在调用BeginEdit方法作为对要调用的CancelEdit方法的响应时返回其状态。但是,在这种情况下,我们并不真正关心能够取消编辑;我们真正需要知道的是用户何时完成了一行的编辑。当DataGrid在绑定项上调用EndEdit时会出现这种情况。

为了通知CustomerDataObjectProvider已在绑定集合中的一个对象上调用EndEdit,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

当项目被添加到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;
}

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

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

总之,此方法将DAL提供的数据项和集合调整为更适合WPF框架内数据绑定的UI项和集合。通过处理来自此绑定集合的事件来执行所有数据库同步逻辑;因此,没有WPF DataGrid特定代码。