ICollectionView用户界面未更新

时间:2020-08-02 06:33:11

标签: c# wpf mvvm collections entity

我有与ICollectionView关联的ObserveCollection(实体) 一切正常,直到我尝试删除该条目。单击“删除”按钮后,界面未更新。 如果我设置了ObserveCollection,那么一切都会很好

private ICollectionView _taskview;
public ICollectionView TasksView 
{
    get { return _taskview; }
    set
    {
        _taskview = value;
        OnPropertyChanged("TaskView");
    }
}
public ICommand DeleteTask
{
    get
    {
        return new DelegateCommand(() =>
        {
            _context.Task.Attach(SelectTask);
            _context.Task.Remove(SelectTask);
            _context.SaveChanges();
            Tasks = new ObservableCollection<TaskModel>(_context.Task);
            TasksView = CollectionViewSource.GetDefaultView(Tasks);
        });
    }
}

public HomeViewModel(Window window)
{
    this.window = window;
    Tasks = new ObservableCollection<TaskModel>(_context.Task);
    TasksView = CollectionViewSource.GetDefaultView(Tasks);
}


  <ListBox Grid.Row="1" Grid.RowSpan="2" Grid.Column="0"
                    SelectionMode="Extended"
                    ItemsSource="{Binding TasksView}"
                    SelectedItem="{Binding SelectTask}">
        </ListBox>

3 个答案:

答案 0 :(得分:0)

在CollectionViewSource的View属性上调用Refresh()以刷新它。

答案 1 :(得分:0)

每次删除后都不要创建新集合。这将对性能产生负面影响。这就是您使用ObservableCollection的原因。这样,绑定目标(例如ListBox)只能更新已更改的项目,而不是重新创建/呈现完整的视图。

在这种情况下,将数据源公开为ICollectionsView也没有意义。而是直接绑定到ObservableCollection

ICollectionsView的源集合像INotifyCollectionChanged一样实现ObservableCollection<T>时,ICollectionView将在源更改时自动更新。
在这种情况下,操作INotifyCollectionChanged集合就足够了。

如果ICollectionsView 的源集合没有像INotifyCollectionChanged那样实现List<T>,则ICollectionView 不会在源更改时自动更新。
在这种情况下,您必须显式调用ICollectionView.Refresh来强制ICollectionView更新。

请注意,您应该从不引用视图模型中的任何视图组件-无例外。这消除了MVVM的所有好处。毫无疑问,这完全没有必要。如果您的视图模型需要引用视图组件,那么您设计的代码或类是错误的。 要遵循此基本和基本的MVVM设计规则,您必须 Window中删除对HomeViewModel的引用。
您可以通过在视图模型上公开一个属性来触发视图行为,该属性是视图中数据触发器的输入。 Patterns - WPF Apps With The Model-View-ViewModel Design PatternThe Model-View-ViewModel Pattern

第一个解决方案(推荐)

您应该直接绑定到Tasks集合。
您需要操纵集合的视图(例如,应用过滤器)时,便使用CollectionViewSource.GetDefaultView(Tasks)来检索视图。但不要束缚它。

<ListBox ItemsSource="{Binding Tasks}" />

public HomeViewModel()
{
  Tasks = new ObservableCollection<TaskModel>(_context.Task);
  Tasks.CollectionChanged += OnTasksChanged;
}

private void OnTasksChanged(object sender, NotifyCollectionChangedEventArgs e)
{
  switch (e.Action)
  {
    case NotifyCollectionChangedAction.Add:
    {
      foreach (TaskModel task in e.NewItems)
      {
        _context.Task.Add(task);
        _context.SaveChanges();
      }
      break;
    }
    case NotifyCollectionChangedAction.Remove:
    {
      foreach (TaskModel task in e.OldItems)
      {
        _context.Task.Attach(task);
        _context.Task.Remove(task);
        _context.SaveChanges();
      }
      break;
    }
  }
}

// Then simply manipulate the 'Tasks' collection
public ICommand DeleteTaskCommand => new DelegateCommand(() => Tasks.Remove(SelectTask));

第二个解决方案

如果您想绑定到ICollectionView,则不再需要其他的ObservableCollection(除了您要在每次添加/移动/保持两个集合和一个ICollectionView的情况下)删除/重置操作)。要更新集合的视图,请调用ICollectionView.Refresh

<ListBox ItemsSource="{Binding TasksView}" />

public HomeViewModel()
{
  TasksView = CollectionViewSource.GetDefaultView(_context.Task);
}


// Then simply refresh the 'TasksView': 
public ICommand DeleteTask => DelegateCommand(
  () =>
  {
    _context.Task.Attach(SelectTask);
    _context.Task.Remove(SelectTask);
    _context.SaveChanges();

    // Update the view
    TasksView.Refresh();
  });

答案 2 :(得分:0)

您有错字:

public ICollectionView TasksView 
{
    get { return _taskview; }
    set
    {
        _taskview = value;
        OnPropertyChanged("TaskView");
    }
}

OnPropertyChanged(“ TaskView”); 上应为OnPropertyChanged("TasksView");