1

我有一个绑定到 EF6 Dbcontext 的 WPF 数据网格。我有很多功能,例如手动编辑等。

问题 编辑绑定到网格的 EF 对象不会在网格上更新。但是,如果我在这些背景编辑之一之后手动编辑单元格,它会立即显示正确的值。

场景/设置

涉及的视源

<Window.Resources>
 <CollectionViewSource x:Key="equipmentViewSource" d:DesignSource="{d:DesignInstance {x:Type HAI_Job_EF_Model:Equipment}, CreateList=True}"/>
 <CollectionViewSource x:Key="equipmentAssociatedDevicesViewSource" 
                              Source="{Binding AssociatedDevices, Source={StaticResource equipmentViewSource}}"/>    
 </Window.Resources>

请注意,关联设备是设备对象内的 ObservableCollection。

WPF 数据网格(仅示例部分)

<DataGrid x:Name="associatedDevicesDataGrid" Grid.Row="1" AutoGenerateColumns="False" 
                              MaxWidth="1200" EnableRowVirtualization="True" 
                              RowDetailsVisibilityMode="VisibleWhenSelected" CanUserDeleteRows="False"
                              DataContext="{StaticResource equipmentAssociatedDevicesViewSource}" ItemsSource="{Binding}" 
                              CellEditEnding="associatedDevicesDataGrid_CellEditEnding" 
                              SelectionChanged="associatedDevicesDataGrid_SelectionChanged" 
                              PreviewKeyDown="associatedDevicesDataGrid_PreviewKeyDown"
                              LostFocus="associatedDevicesDataGrid_LostFocus">
                <DataGrid.Resources>
                    <!-- DATGRID STYLE CELL: Gives padding space inside cells -->
                    <Style TargetType="DataGridCell">
                        <Setter Property="Padding" Value="5,5"/>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type DataGridCell}">
                                    <Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                                        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </DataGrid.Resources>
                <DataGrid.Columns>
                    <DataGridTextColumn x:Name="quantityColumn" Header="Qty" MaxWidth="50" 
                                        Binding="{Binding Quantity, StringFormat={}\{0:N0\}, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
                    <DataGridComboBoxColumn x:Name="typeColumn" Header="Type" MaxWidth="150" 
                                            ItemsSource="{Binding Source={StaticResource assDevTypeFilteredViewSource}}"
                                            SelectedItemBinding="{Binding Path=Type, UpdateSourceTrigger=PropertyChanged}" 
                                            TextBinding="{Binding Path=Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                        <DataGridComboBoxColumn.EditingElementStyle>
                            <Style TargetType="ComboBox">
                                <Setter Property="IsEditable" Value="True"/>
                                <Setter Property="Text" Value="{Binding Path=Type}"/>
                                <Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
                                <Setter Property="IsTextSearchEnabled" Value="True" />
                                <Setter Property="IsTextSearchCaseSensitive" Value="False" />
                            </Style>
                        </DataGridComboBoxColumn.EditingElementStyle>
                    </DataGridComboBoxColumn>

                    <DataGridTemplateColumn x:Name="certificateNumberColumn" Header="Certificate Number" Width="Auto" MaxWidth="200">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox Name="cbxAssDevCertComboBox" 
                                          IsEditable="True" IsTextSearchEnabled="True" IsTextSearchCaseSensitive="False"
                                          ItemsSource="{Binding GenericFilterResults}"
                                          Text="{Binding Path=CertificateNumber, UpdateSourceTrigger=PropertyChanged}"
                                          SelectionChanged="cbxAssDevCertComboBox_SelectionChanged"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn x:Name="manufacturerColumn" Header="Manufacturer" Width="Auto" MaxWidth="150" 
                                        Binding="{Binding Manufacturer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

背景更改 组合框“cbxAssDevCertComboBox” selectionchanged 事件然后更新其他单元格源对象的所有值。这是不刷新的更新。

尝试/考虑的主要选项

  1. 我没有完全了解 MVVM,也没有关注它。我现在太深了,无法为这个项目做出改变。我只需要更新f'n的东西......!

  2. 我不能将每一个 EF 对象都包装在一个 Observable 集合中……没有其他东西需要它,为什么会这样呢?这不是 CollectionViewSource 本质上在做什么吗?!

  3. 更新 Datagrids ItemSource 绑定表达式没有帮助。

  4. 使用更新

当我在程序编辑后手动尝试编辑单元格时,如何更新单元格?

我现在已经失去了几天试图解决这个问题;任何帮助将不胜感激。

4

2 回答 2

2

AnObservableCollection很棒,但它只在添加或删除项目时通知 UI。修改项目时(即更改项目属性时),它不会通知 UI。

您需要INotifyPropertyChanged在模型上实现接口并启动它。

这是一个实现接口的示例模型类:

public class ModelClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }

    string _myValue;
    public string MyValue
    {
        get
        {
            return _myValue;
        }
        set
        {
            _myValue = value;
            OnPropertyChanged(() => MyValue);
        }
    }
}

漂亮的 lambda 技巧取自这个 SO question ...

当然,您可以OnPropertyChanged从代码的其他部分手动调用(根据需要调整访问器或编写额外的公共方法)。调用OnPropertyChanged应该强制 UI 为显示的属性调用 getter。

于 2013-09-25T07:53:01.433 回答
2

为其他信息解决

我找到了答案。我想知道为什么我的其他一些网格更新了,而这个没有。

如果您像我在 OP 中显示的那样创建视图源;调用 ViewSource.View.Refresh 将刷新网格。我最初没有这个,因为它在刷新时会导致 ComboboxSelectionChanged 事件;然后在无限循环中创建。您也不能只添加一个切换,以防止事件的每秒钟刷新一次,因为此事件也可以在设置过程中多次触发。

解决方案 我使用 bool 作为锁来防止处理选择更改事件中的逻辑。每次处理事件逻辑时都会设置此锁。只有 Combobox drop open 事件才能解除锁定;这可确保刷新仅在用户进行选择更改时按预期发生。

于 2013-09-25T21:52:51.523 回答