无法检测绑定到EF导航属性MVVM的Datagrid记录中的更改(与listview一起使用)

时间:2013-03-26 05:44:25

标签: .net wpf entity-framework mvvm entity-framework-5

我有一个使用MVVM模型和Entity Framework 5进行数据访问的WPF应用程序。我有一个用户控件,其中包含员工的master / detials视图。员工列表的列表视图和“详细信息”网格,其datacontext设置为列表视图的选定员工。在该网格中,我有一个数据网格,该数据网格绑定到所选员工的导航属性(名为employee_certification的属性)。所有绑定都能正常工作,即使在输出窗口中也没有错误。

问题:我的问题是我无法检测用户是否对导航属性的记录进行了任何更改。我目前使用更改跟踪器来测试实体中的更改,以启用某些命令按钮,如保存,撤消等。但更改跟踪器永远不会检测导航属性中的(称为employee_certification)。

以下是我从模型中获取员工实体的方法:

    Public Function GetEmployee_All(Context As FTC_Context) As ObservableCollection(Of employee) Implements IEmployeeDataService.GetEmployee_All
        Dim employees = Context.employees.Include("employee_certification").ToList            
        Return New ObservableCollection(Of employee)(employees)
    End Function

以下是导航属性与datagrid的绑定。 (哪个有效,这意味着它确实显示了正确的记录)

<DataGrid  Grid.Column="1" Grid.Row="2" MinWidth="350"        
            ItemsSource="{Binding ElementName=DetailControl, Mode=TwoWay, Path=DataContext.employee_certification}" 
            CanUserAddRows="False" CanUserDeleteRows="False" >
    <DataGrid.Columns>
    </DataGrid.Columns>
</DataGrid>

即使绑定有效并且显示了正确的记录,我也无法确定用户是否对导航属性的记录进行了更改。

目标:我希望能够通过上下文本身检测更改,如果可能的话。我不想编写一个帮助类来将当前记录与数据库原件进行比较。有人可以帮我这么做吗?

编辑#1: 我认为它可能与数据网格有关。我在我的应用程序中的另一个usercontrol中有以下listview,并且可以通过EF上下文跟踪对listviews记录中的记录字段所做的任何更改。

listview,其中绑定vendor_account是实体vandor的导航属性:

 <ListView Grid.Column="1" Grid.Row="2"
           Style="{DynamicResource FTC_SubListView}"
           ItemContainerStyle="{DynamicResource FTC_SubListViewItem}"
           ItemsSource="{Binding vendor_account, Mode=TwoWay}"
           ItemTemplate="{DynamicResource FTC_VendorAccountsTemplate}"  />

以下是我如何确定是否有更改以在我的视图中启用保存按钮:

    Private Function CanSaveExecute() As Boolean
        If _Selection.HasErrors = False Then
            If (From entry In Context.ChangeTracker.Entries(Of vendor)() Where entry.Entity.idVendor = _Selection.idVendor And entry.State = EntityState.Modified Select entry).Count > 0 Then
                Return True
            ElseIf (From entry In Context.ChangeTracker.Entries(Of vendor_account)() Where entry.Entity.idVendor = _Selection.idVendor And (entry.State = EntityState.Modified Or entry.State = EntityState.Added) Select entry).Count > 0 Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

但如果我对数据网格使用以下内容,则它永远不会有emplopyee_certification导航属性的更改计数:

    Private Function CanSaveExecute() As Boolean
        If _Selection.HasErrors = False Then
            If (From entry In Context.ChangeTracker.Entries(Of employee)() Where entry.Entity.idEmployee = _Selection.idEmployee And entry.State = EntityState.Modified Select entry).Count > 0 Then
                Return True
            ElseIf (From entry In Context.ChangeTracker.Entries(Of employee_certification)() Where entry.Entity.idEmployee = _Selection.idEmployee And entry.State = EntityState.Modified Select entry).Count > 0 Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

有谁知道为什么我的listview允许更改跟踪器从更改跟踪器中查看x个已更新的实体,但不能查看数据网格?

编辑#2

好的,所以我缩小范围,我将listview和datagrid放在同一个usercontrol上,并将它们以相同的方式绑定到对象的datacontext的导航属性,如上所述。员工将证书作为链接记录,这是员工对象的导航属性(employee_certification)。

如果我对employee_certification记录使用listview,那么当我对这些记录进行更改时,我可以查询更改跟踪器以计算更改,并在计数大于零时启用保存和撤消按钮。

 From entry In Context.ChangeTracker.Entries(Of employee_certification)() Where entry.Entity.idEmployee = _Selection.idEmployee And entry.State = EntityState.Modified Select entry).Count

当我使用datagrid并更改employee_certification记录中的任何字段时,更改跟踪器不会将其中的任何字段标记为已修改。

这里是如何定义datagrid / listview的

 <DataGrid  Grid.Column="1" Grid.Row="2" MinWidth="350"        
            ItemsSource="{Binding employee_certification, Mode=TwoWay}" 
            CanUserAddRows="False" CanUserDeleteRows="False" >
    <DataGrid.Columns>
        <!--  Custom Defined Columns Go Here  -->
    </DataGrid.Columns>
</DataGrid>
<ListView Grid.Column="1" Grid.Row="3"
            Style="{DynamicResource FTC_SubListView}"
            ItemContainerStyle="{DynamicResource FTC_SubListViewItem}"
            ItemsSource="{Binding employee_certification, Mode=TwoWay}"
            ItemTemplate="{DynamicResource MyTemplate}">
</ListView>

我想使用datagrid,因为内置排序等。

编辑问题#2 :为什么更改跟踪器跟踪列表视图编辑中的更改但不跟踪数据网格编辑?

1 个答案:

答案 0 :(得分:0)

这非常令人沮丧。正如标题所暗示的那样,我认为问题在于实体框架,可观察集合和数据网格的某些交互。事实证明,这只是DataGridTemplateColumn的绑定声明的一个问题。

根据SO ANSWER, 使用自己的DataGridTemplateColumn时,DataGrid会将所有绑定上的UpdateSourceTrigger更改为Explicit。这必须由事件处理。但是,我正在使用MVVM模式,并且不希望事件处理单元格更改。我希望更改自动反映回我的viewmodel中的集合,所以我必须显式声明这样的列绑定:(即对于组合框)

 SelectedValue="{Binding idCertification, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=LostFocus}"

我必须添加UpdateSourceTrigger = LostFocus才能将更改反映回可观察的集合。现在我能够直接绑定到导航属性,并使用实体框架中的 Context.changeTracker 来计算更改(employee_certification,如上面的问题所示),以便启用保存和撤消命令。

两天的搜索发现它只是对绑定的一个简单补充,arrrgh。