Пользовательский интерфейс ICollectionView не обновляется - PullRequest
0 голосов
/ 02 августа 2020

У меня есть ObserveCollection (entity), связанный с ICollectionView. Все работает нормально, пока я не попытаюсь удалить запись. После нажатия на кнопку «удалить» интерфейс не обновляется. Если я установил 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 голосов
/ 03 августа 2020

Не создавайте новую коллекцию после каждого удаления. Это отрицательно скажется на производительности. Это причина, по которой вы используете ObservableCollection. Таким образом, цель привязки, например, ListBox, может обновлять только измененные элементы, вместо воссоздания / рендеринга полного представления.

В этом контексте также не имеет смысла раскрывать данные исходный код ICollectionsView. Скорее привязывайтесь к ObservableCollection напрямую.

Когда исходная коллекция ICollectionsView реализует INotifyCollectionChanged, как ObservableCollection<T>, тогда ICollectionView будет автоматически обновляться при изменении источника. В этом случае достаточно манипулировать коллекцией INotifyCollectionChanged.

Когда исходная коллекция ICollectionsView не реализует INotifyCollectionChanged как List<T>, тогда ICollectionView не будет автоматически обновляться при изменении источника. В этом случае вы должны явно вызвать ICollectionView.Refresh, чтобы принудительно обновить ICollectionView.

Обратите внимание, что никогда не должны ссылаться на какие-либо компоненты представления в вашей модели представления - без исключений. Это исключает все преимущества MVVM. И это наверняка никогда не нужно. Если ваша модель представления требует ссылки на компонент представления, вы неправильно проектируете свой код или классы. Чтобы следовать этому основному c и фундаментальному правилу проектирования MVVM, вы должны удалить ссылку на Window из HomeViewModel. Вы можете инициировать поведение представления, выставив свойство в модели представления, которое является входом для триггера данных в представлении. Шаблоны - приложения WPF с шаблоном проектирования Model-View-ViewModel , Шаблон Model-View-ViewModel .

Первое решение (рекомендуется)

Вы должны напрямую привязаться к коллекции 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();
  });
0 голосов
/ 05 августа 2020

У вас есть опечатка:

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

В OnPropertyChanged ("TaskView"); должно быть OnPropertyChanged("TasksView");

0 голосов
/ 02 августа 2020

Вызвать Refre sh () в свойстве View CollectionViewSource, чтобы обновить его.

...