如何正确处理datagrid的CollectionChanged事件?

时间:2016-03-03 08:01:16

标签: c# xaml datagrid observablecollection collectionview

我最初向Entity Framework here提出了与dataGrid插入/删除/保存操作相关的问题但是我无法完全获得建议的工作方法。到目前为止,这是我的方法:

ViewModel构造函数

public DeviceDatabaseViewModel()
{
    LoadData();
}

LoadData

private void LoadData()
{
    _context.Devices.Load();
    _devices = _context.Devices.GetLocal();

    _devices.CollectionChanged += Device_CollectionChanged;

    DeviceCollectionView = (CollectionView)new CollectionViewSource { Source = _devices }.View;
}

事件

private bool _isAddedbyApp = false;

private void Device_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    var device = new Device();
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            foreach (var item in e.NewItems)
            {
                var entity = item as Device;
                if (entity == null) continue;
                if (_isAddedbyApp) continue;

                _isAddedbyApp = true;
                _context.Devices.Add(entity);
                _isAddedbyApp = false;
            }
            break;
        case NotifyCollectionChangedAction.Remove:
            foreach (var item in e.OldItems)
            {
                var entity = item as Device;
                if (entity == null) continue;
                if (_isAddedbyApp) continue;

                _isAddedbyApp = true;
                _context.Devices.Remove(entity);
                _isAddedbyApp = false;
            }
            break;
        //Reset = Clear
        case NotifyCollectionChangedAction.Reset:

            break;
    }
}

XAML

<DataGrid 
          x:Name="DeviceListDataGrid" 
          Margin="0,25,0,0"
          Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="6"
          AutoGenerateColumns="False" 
          EnableRowVirtualization="True" 
          AlternatingRowBackground="LightBlue" 
          AlternationCount="2" 
          RowDetailsVisibilityMode="VisibleWhenSelected"
          ItemsSource="{Binding DeviceDatabaseViewModel.DeviceCollectionView}" 
          SelectedItem="{Binding DeviceDatabaseViewModel.SelectedDevice}">
    <DataGrid.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="DarkCyan"/>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="DarkCyan"/>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTextColumn x:Name="DeviceIdentification" Header="Id" Width="200*" Binding="{Binding DeviceId, UpdateSourceTrigger=PropertyChanged}"  />
        <DataGridTextColumn x:Name="DeviceName" Header="Name" Width="200*" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  />
        <DataGridTextColumn x:Name="DeviceDescriptionColumn" Header="Description" Width="200*" Binding="{Binding Description, UpdateSourceTrigger=PropertyChanged}"/>
        <DataGridTextColumn x:Name="DeviceSupplier" Header="Supplier" Width="150*" Binding="{Binding Supplier, UpdateSourceTrigger=PropertyChanged}"/>
        <DataGridTextColumn x:Name="DeviceCategory" Header="Category" Width="150*" Binding="{Binding Category, UpdateSourceTrigger=PropertyChanged}"/>
    </DataGrid.Columns>
</DataGrid>

GetLocal从实体框架数据库返回ObservableCollection,该数据库也正在实施INotifyPropertyChanged

但是我无法为实体框架的SaveChanges方法找到正确的位置,而且结构似乎有点偏离?

修改

如果我在活动结束时SaveChanges放置了CollectionChanged我的程序会挂起。实际上我有一些调试原因在SaveChanges()方法中有一个MessageBox,在禁用之后,事情似乎或多或少都朝着正确的方向发展..

编辑2 添加设备实体定义。 Link to the file,因为它相当长......

MessageBox是通过此例外

生成的
  

{“ItemsControl与其项目源不一致。\ n请参阅   内部异常以获取更多信息。“}

     

{“开发人员的信息(使用Text Visualizer阅读   这个):\ r \ n这个异常被抛出,因为生成器用于控制   'System.Windows.Controls.DataGrid Items.Count:28'的名称   'DeviceListDataGrid'已收到CollectionChanged事件序列   不同意Items集合的当前状态。该   检测到以下差异:\ r \ n累计计数27为   与实际计数28不同。[累计计数为(最后计数)   重置+ #Adds - 自上次复位后#Removes。)\ r \ n在索引26处:   Generator的项目“{NewItemPlaceholder}”与实际项目不同   'FxEditorDatabaseStructure.Core.Domain.Device'。\ r \ n \ r \ n一个或多个   以下来源可能引发了错误的事件:\ r \ n
  System.Windows.Controls.ItemContainerGenerator \ r \ n
  System.Windows.Controls.ItemCollection \ r \ n
  System.Windows.Data.ListCollectionView \ r \ n
  System.Collections.ObjectModel.ObservableCollection`1 [FxEditorDatabaseStructure.Core.Domain.Device,   FxEditorDatabaseStructure,Version = 1.0.0.0,Culture = neutral,   PublicKeyToken = null]] \ r \ n(已加星标的来源被认为更多   可能是导致问题的原因。)\ r \ n \ r \ n最常见的原因   是(a)更改集合或其计数而不提高   相应的事件,以及(b)提出索引不正确的事件   或项目参数。\ r \ n \ r \ n例外的堆栈跟踪描述了如何   检测到不一致,而不是它们是如何发生的。得到一个   更及时的例外,设置附加属性   生成器上的'PresentationTraceSources.TraceLevel'值为'High'   并重新运行该方案。一种方法是运行命令   类似如下:\ n
  System.Diagnostics.PresentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator,   System.Diagnostics.PresentationTraceLevel.High)\ r \ n来自Immediate   窗口。这导致检测逻辑在每次运行之后运行   CollectionChanged事件,因此会降低应用程序的速度。\ r \ n“}

     

开发人员的信息(使用Text Visualizer来阅读):这个   异常被抛出,因为生成器用于控制   'System.Windows.Controls.DataGrid Items.Count:28'的名称   'DeviceListDataGrid'已收到CollectionChanged事件序列   不同意Items集合的当前状态。该   检测到以下差异:累计计数27为   与实际计数28不同。[累计计数为(最后计数)   重置+ #Adds - 自上次重置后#Removes。)在索引26处:   Generator的项目“{NewItemPlaceholder}”与实际项目不同   'FxEditorDatabaseStructure.Core.Domain.Device'。

1 个答案:

答案 0 :(得分:1)

有几件事:

首先,您可以直接绑定到_devices或您的热门ObservableCollection变量,无需创建DeviceCollectionView

ItemsSource="{Binding DeviceDatabaseViewModel._devices}"

请务必进行_devices公开访问。

其次,Device_CollectionChanged函数存在问题,如果您应用上述更改,则可以这样做:

private bool _isAddedbyApp = false;

private void Device_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            foreach (var item in e.NewItems)
            {
                MessageBox.Show(item.GetType().ToString()); // if not = "Device" then tell me because there something you bind don't correct
                var entity = item as Device;
                if (entity != null && !_isAddedbyApp)
                {
                    if (MessageBox.Show("Add?", "", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                    {
                        // add entity to database
                        // No need to call _devices.Add() here, you collection
                        // will auto be updated.
                    }
                    else
                    {
                        // remove this item
                        _devices.Remove(entity);
                    }
                }
            }
            break;
    }
}

第三,您仍然不知道如何使用_isAddedbyApp变量。

仅在您的应用(非用户)添加设备时使用它。

_isAddedbyApp = true;   // You start add items.
_context.Add(...);
_isAddedbyApp = false;  // You finished add items.
相关问题