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; }
}
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());
}
}
}
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
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());
}
3条答案
按热度按时间j1dl9f461#
CodeProject上有一篇关于WPF DataGrid + MVVM模式的文章:
http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx
jq6vz3qz2#
我不知道有什么关于这个主题的好文章,但我看不出有什么问题;只要绑定到ObservableCollection或ListCollectionView,其中包含的对象类具有默认构造函数(我认为没有其他限制),DataGrid就能很好地处理这些事情。你绑定到的集合必须有一些添加新项的方法,这就是为什么你需要绑定到ICollection或IEditableCollectionView -后者是首选,因为它有控制项创建的特定选项-参见
AddNew
,CanAddNew
等,DataGrid可以很好地使用它们。z4bn682m3#
编辑:粘贴了符合您问题的部分。全文:http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples
这个示例演示了如何使用DataGrid通过绑定执行CRUD操作,其中数据库集成通过数据访问层(DAL)解耦。
建筑
此示例是一个简单的CRUD应用程序,它允许用户编辑Northwind数据库的Customers表中的项。这个例子有一个数据访问层,它公开了在简单数据对象上操作的查找/删除/更新方法,还有一个表示层,它以一种可以有效地被WPF框架绑定的方式来适应这些对象。因为我们只是执行CRUD功能,所以我没有添加业务逻辑层(BLL);如果您是一个纯粹主义者,您可以添加一个直通BLL;但是,我觉得这对这个例子没有什么帮助。
此体系结构中的关键类如下所示:
数据访问层公开了一个用于管理客户数据对象生命周期的接口。实现此接口的类使用类型化DataSet作为数据库集成层;然而,这对DAL的客户端是隐藏的。该层的存在意味着我们不直接耦合到数据库模式或生成的数据集模式,即。也就是说,我们可以改变我们的模式,但仍然向我们的客户提供下面给出的接口:
正如您所看到的,DAL没有公开UI框架特定的接口或类(如ObservableCollection)。这里的问题是如何绑定ICustomerDataAccess返回的客户。获取客户到我们的数据网格,并确保更改与数据库同步。
我们可以将DataGrid直接绑定到我们的客户集合List;但是,我们需要确保在适当的时间点调用DAL接口上的UpdateCustomer和DeleteCustomer方法。我们可能采取的一种方法是处理DataGrid公开的事件/命令,以确定它刚刚对绑定的客户集合执行了什么操作或打算执行什么操作。但是,这样做的话,我们将编写特定于DataGrid的集成代码。如果我们想改变UI来呈现一个ListView和一些TextBox(详细信息视图),该怎么办?我们必须重写这个逻辑。此外,没有一个DataGrid事件完全符合我们的需要。存在“正在结束”事件,但不存在“已结束”事件;因此,对事件处理程序可见的数据不处于其提交状态。一个更好的方法是,如果我们可以调整我们的客户对象集合,使它们可以绑定到任何合适的WPF UI控件,通过我们的DAL与数据库同步添加/编辑/删除操作。处理删除操作
ObservableCollection类是我们数据绑定需求的一个很好的候选对象。它公开一个CollectionChanged事件,每当向集合中添加项或从集合中移除项时都会触发该事件。如果我们将客户数据复制到ObservableCollection中并将其绑定到DataGrid,我们就可以处理CollectionChanged事件并对DAL执行所需的操作。下面的代码片段显示CustomerObjectDataProvider(在XAML中定义为ObjectDataProvider)如何构造CustomerUIObjects的ObservableCollection。这些UI对象简单地 Package 它们的数据对象对应物,以便公开相同的属性。
当用户使用DataGrid控件删除行时,将对绑定集合激发CollectionChanged事件。在事件处理程序中,我们调用DAL DeleteCustomer方法,并将 Package 的数据对象作为参数传递。
处理删除操作相对简单,但是更新或插入操作呢?您可能认为可以使用相同的方法,即NotifyCollectionChangedEventArgs。Action属性不包括Add操作;但是,当更新集合中的项时,不会激发此事件。此外,当用户向DataGrid添加新项时,该对象最初以非初始化状态添加到绑定集合中,因此我们只能看到具有默认属性值的对象。我们真正需要做的是确定用户何时完成编辑网格中的项。处理更新/插入
要确定用户何时完成编辑绑定项,我们需要更深入地研究绑定机制本身。DataGrid能够对当前正在编辑的行执行原子提交;如果绑定项实现了IEditableObject接口,该接口公开了BeginEdit、EndEdit和CancelEdit方法,则这是可能的。通常,实现此接口的对象将返回到调用BeginEdit方法作为对调用CancelEdit方法的响应时的状态。然而,在这种情况下,我们并不真正关心是否能够取消编辑;我们真正需要知道的是用户何时完成编辑行。当DataGrid对我们的绑定项调用EndEdit时,这将被指示。
为了通知CustomerDataObjectProvider已对绑定集合中的某个对象调用EndEdit,CustomerUIObject按如下方式实现IEditableObject:
将项添加到CustomerUIObjects集合时,将为集合中的所有项处理此事件,处理程序仅转发该事件:
CustomerObjectDataProvider现在可以处理此事件,以接收对任何绑定项调用CommitEdit的通知。然后,它可以调用DAL方法来同步数据库状态:
上面的代码将处理插入和更新操作。
总之,该方法将DAL提供的数据项和集合调整为更适合WPF框架内的数据绑定的UI项和集合。所有数据库同步逻辑都是通过处理来自该绑定集合的事件来执行的;因此,没有特定于WPF DataGrid的代码。