【问题标题】:ICollectionView ui is not updatedICollectionView ui 未更新
【发布时间】:2020-08-02 06:33:11
【问题描述】:

我有与 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>

【问题讨论】:

  • ObservableCollection implements 有事件CollectionChanged 表示“重绘”。坚持使用它,否则在删除操作后调用OnPropertyChanged
  • 我也试过了,但是删除后界面中的记录数还是没有变化

标签: c# wpf mvvm collections entity


【解决方案1】:

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

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

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

ICollectionsView 的源集合没有List&lt;T&gt; 一样实现INotifyCollectionChanged,那么ICollectionView 不会在源更改时自动更新.
在这种情况下,您必须显式调用 ICollectionView.Refresh 以强制更新 ICollectionView

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

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

    【讨论】:

    • 不要在委托中创建新的任务视图实例,更新上下文并在调用刷新之后。
    • 有趣的是,使用 observecollection 一切正常,同时我在调试器中查看 icollectionview 并更新其数据,然后 onproperty 工作,但是,UI 仍然没有改变不知为何,很奇怪
    • 你能分享你的仓库吗?
    • 很抱歉,如果格式不便,这里是zip链接:fayloobmennik.cloud/7401165(没有上传可怕的东西到github)
    【解决方案3】:

    你有一个错字:

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

    OnPropertyChanged("TaskView"); 应该是OnPropertyChanged("TasksView");

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 2020-07-27
      相关资源
      最近更新 更多