WPF在SP1中更好的数据编辑功能

[原文作者]:Beth Massi    
[原文链接]:Better Data Editing Features in WPF with SP1       
 
 
   当我开始钻研数据绑定时,在WPF中我最想念的一项功能,是在BindingListCollectionView和我所喜欢的winforms BindingSource之间的一致性功能。BindingListCollectionView就像在winforms下的资源捆绑一样,提供了限制收集数据(或数据表)的导航、流动、过滤和排序。
   然而在合集中并不支持处理添加和删除项目。你可以从我的WPF窗体数据录像中注意到,当我从数据中添加或者删除一行时,我只能直接进入数据表进行操作。当我用数据表工作时这不会有问题,因为他们可以做他们自己的处理编辑(连同修改记录)。不过,为了有良好的客户业务集合,实现典型的绑定接口,这通常是一个必要的功能
SP1在WPF’s BindingListCollectionView中增加了新的属性和方法
   发布的Visual Studio/.NET FX SP1已经增强了BindingListCollectionView,包括新的属性和方法:CanAddNew 属性, CanCancelEdit 属性, CanRemove属性, CurrentAddItem属性, CurrentEditItem属性, IsAddingNew属性, IsEditingItem属性, ItemProperties属性, NewItemPlaceholderPosition属性, AddNew方法, CancelEdit 方法, CancelNew 方法, CommitEdit 方法, CommitlNew 方法, EditItem 方法, Remove 方法, RemoveAt 方法.
   有一件事情我想在这里指出,不同的是,在Winforms中,无论是修改或增加数据源(也就是数据表或集合),我们都习惯于访问BindingSource上的EndEdit来实现处理变换。在WPF中,有一个CommitEditCommitNew的单独访问,如果在增加的时候调用了AddNew,你必须要确认你不是在调用CommitEdit,否则你就只能调用CommitNew。我不知道他们为什么把这两者区分开来。在使用DataSets时,我总是几乎立刻提交处理(如在填写默认值后),并且可以通过Accept/RejectChanges方法来使用DataSet的修改记录。
 
用新的AddNew和Remove Methods来增加或删除数据
   当我们想在数据表中增加一行新的数据,我们现在可以直接调用BindingListCollectionView中的AddNew。例如:
Private OrderData As New OrdersDataSet
Private OrdersViewSource As BindingListCollectionView
Sub New()
    ‘ This call is required by the Windows Form Designer.
    InitializeComponent()
 
    ‘ Add any initialization after the InitializeComponent() call.
    Me.LoadData()
    Me.DataContext = Me.OrderData.Orders
    Me.OrdersViewSource = CollectionViewSource.GetDefaultView(Me.DataContext)
End Sub
Private Sub AddNewOrder()
    ‘— Old Code —
    ‘Add a new row to the collection
    ‘Dim order = Me.OrderData.Orders.NewOrdersRow
    ‘Me.OrderData.Orders.AddOrdersRow(order)
    ‘Up to us to update the position
    ‘Me.OrdersViewSource.MoveCurrentToLast()
 
    ‘— New Code —
    ‘Add a new row to the collection
    Me.OrdersViewSource.AddNew()
    ‘Push changes into the DataTable
    Me.OrdersViewSource.CommitNew()
End Sub
 
 
   首先我通过DataSetpartial类来处理所有的验证和设置的默认值,因此如果我们工作于自己的商业对象集合时,AddNewOrder()方法仍将保持不变。这就是为什么我习惯于用Winforms,因为你可以轻松地交换数据源,又不会弄乱数据绑定代码。不过需要指出的是,如果CommitNewDataRow无法被调用,你再写入DataSet时就会报错。所以一定要确保调用在数据表partial类中的TableNewRow事件,并且写入有效的默认值。
删除当前行也简单:
Private Sub RemoveOrder()
    If Me.OrdersViewSource.CurrentPosition > -1 Then
        ‘— Old Code —
        ‘Dim order As OrdersDataSet.OrdersRow
        ‘order = CType(CType(Me.OrdersViewSource.CurrentItem, DataRowView).Row, OrdersDataSet.OrdersRow)
        ‘order.Delete()
 
        ‘— New Code —
        Me.OrdersViewSource.Remove(Me.OrdersViewSource.CurrentItem)
    End If
End Sub 
 
WPF中使用Master-Detail窗体
 
   这些都是很好的改进,但是由于BindingSource是一个可视化的组件,并且能够处理CurrencyManager 目前Winforms中的BindingSource仍然比IMHO方便。当你在WPF中用master-detail绑定是一件痛苦的事情。你必须获得一个BindingListCollectionView的详细引用,每次detail view有变动,都需要再次引用(这将是ListBox或者ListView上的一个ItemSource)。如果你在XAML中能正确地建立绑定,那么当父模块变换时detail view就会自动变换。然而,如果你想在子模块中用AddNew,你就需要实时在每次都获得一个代码的引用,因为视图是动态的。Winforms 绑定源处理这种情况更好些。
   尽管我们需要每次都获得引用,这也是相当简单的:
Private Sub AddNewDetail()
    If Me.OrdersViewSource.CurrentPosition > -1 Then
        ‘— Old Code —
        ‘Dim order As OrdersDataSet.OrdersRow
        ‘order = CType(CType(Me.OrdersViewSource.CurrentItem, DataRowView).Row, _
        ‘              OrdersDataSet.OrdersRow)
        ‘Dim detail = Me.OrderData.OrderDetail.NewOrderDetailRow
        ‘detail.OrderID = order.OrderID
        ‘Me.OrderData.OrderDetail.AddOrderDetailRow(detail)
 
        ‘— New Code —
        Dim detailView As BindingListCollectionView = _
                          CollectionViewSource.GetDefaultView(Me.lstDetails.ItemsSource)
        detailView.AddNew()
        ‘Note that the related OrderID is set for us automatically just like Winforms
        detailView.CommitNew()
    End If
End Sub
 
Private Sub RemoveDetail()
    If Me.OrdersViewSource.CurrentPosition > -1 Then
 
        Dim detailView As BindingListCollectionView = _
                          CollectionViewSource.GetDefaultView(Me.lstDetails.ItemsSource)
 
        If detailView.CurrentPosition > -1 Then
            ‘— Old Code —
            ‘Dim detail As OrdersDataSet.OrderDetailRow
            ‘detail = CType(CType(Me.OrderDetailsViewSource.CurrentItem, DataRowView).Row, _
            ‘               OrdersDataSet.OrderDetailRow)
            ‘detail.Delete()
 
            ‘— New Code —
            detailView.Remove(detailView.CurrentItem)
        End If
    End If
End Sub
 
   通过使用新的AddNewRemove方法似乎也能解决一些问题,我曾经遇到过使用LINQ to SQL产生子模块集合(EntitySets),所以最好开始运用这些新方法的优势。在以后的博客帖子中,我会用我们所做的LINQ to SQL N-Tier application,在末尾补上WPF Front
   我可能不会更新我们已经做的工作的视频,但以后我会在适当的时候使用这些新的方法和属性,所以请下载SP1
Enjoy!

发表评论