Не обновляется ListBox после удаления элемента
реализую проект MWWM паттерном, CRUD элементов осуществляется через команды (Lambda(Relay)Command). Не удаляется из View CategorySearchWord после удаления.
Вот View
<GroupBox Header="Горячие слова">
<ListBox ItemsSource="{Binding SelectedCategory.CategorySearchWords}" SelectedItem="{Binding SelectedCategorySearchWord}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center" FontSize="16"/>
<Button Content="X"
Command="{Binding DataContext.RemoveCategorySearchWordCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"
HorizontalAlignment="Right" Width="50"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
Команда во ViewModel
#region Command RemoveCategorySearchWordCommand - Remove category
/// <summary>Remove category</summary>
private ICommand _RemoveCategorySearchWordCommand;
/// <summary>Remove category</summary>
public ICommand RemoveCategorySearchWordCommand => _RemoveCategorySearchWordCommand
??= new LambdaCommand(OnRemoveCategorySearchWordCommandExequted, CanRemoveCategorySearchWordCommandExequt);
/// <summary>Checking the possibility of execution - Remove category</summary>
public bool CanRemoveCategorySearchWordCommandExequt(object p) =>
p is CategorySearchWord categorySearchWord
&& SelectedCategorySearchWord is not null
&& categorySearchWord is not null;
/// <summary>Execution logic - Remove category</summary>
public void OnRemoveCategorySearchWordCommandExequted(object p)
{
var categorySearchWord_to_remove = p ?? SelectedCategorySearchWord;
if (!(categorySearchWord_to_remove is CategorySearchWord categorySearchWord)) return;
if (!_UserDialog.ConfirmInformation($"Вы уверены, что хотите удалить категорию {categorySearchWord.Name}?", "Удаление категории")) return;
_CategorySearchWordRepository.Remove(categorySearchWord.Id);
SelectedCategory.CategorySearchWords.Remove(categorySearchWord);
if (ReferenceEquals(SelectedCategorySearchWord, categorySearchWord)) SelectedCategorySearchWord = null;
UpdateCategorySearchWordsView(SelectedCategory); //перевыбирает SelectedCategory для обновления отображения,
}
#endregion
При добавлении/изменении View корректно отображает/обновляет данные. Единственное, что у меня корректно сработало для обновления View после удаления, это полная перевыгрузка ObservalCollection из БД...Но это хрень какая-то. (OnPropertyChanged(...), удаление и добавление обратно в ObservalCollection SelectedCategory целиком тоже результата не дали)
При том при отладке видно что categorySearchWord как из удаляется как из БД так и из коллекции, а в отображении остаётся висеть, при повторном удалении выкидывает ошибку.
#region CategoryListBox SelectedCategory
private Category _SelectedCategory;
/// <summary>SelectedCategory in CategoryListBox</summary>
public Category SelectedCategory
{
get => _SelectedCategory;
set => Set(ref _SelectedCategory, value);
}
#endregion
public class Category : NamedEntity //сущность из БД
{
public ICollection<ProductBase> Products { get; set; }
public ICollection<CategorySearchWord> CategorySearchWords { get; set; }
}
internal abstract class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string PropertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
protected virtual bool Set<T>(ref T field, T value, [CallerMemberName] string PropertyName = null)
{
if (Equals(field, value)) return false;
field = value;
OnPropertyChanged(PropertyName);
return true;
}
}
Экспериментирую тут, вот такой вариант обновляет интерфейс, но это тоже не айс
var vvv = SelectedCategory.CategorySearchWords.ToArray();
SelectedCategory.CategorySearchWords.Clear(); //рабочий вариант, тогда не понятно почему не реагирует на Remove...
foreach (var item in vvv)
{
if (item is null) return;
SelectedCategory.CategorySearchWords.Add(item);
}
Ответы (1 шт):
Дописал вот такую модель данных, всё заработало.
class CategoryModel : Category
{
public CategoryModel()
{
ProductsObsColl = (Products is null) ? new ObservableCollection<ProductBase>() : new ObservableCollection<ProductBase>(Products);
CategorySearchWordsObsColl = (CategorySearchWords is null) ? new ObservableCollection<CategorySearchWord>() : new ObservableCollection<CategorySearchWord>(CategorySearchWords);
}
public CategoryModel(Category category)
{
Id = category.Id;
Name = category.Name;
Products = category.Products;
CategorySearchWords = category.CategorySearchWords;
ProductsObsColl = (Products is null) ? new ObservableCollection<ProductBase>() : new ObservableCollection<ProductBase>(Products);
CategorySearchWordsObsColl = (CategorySearchWords is null) ? new ObservableCollection<CategorySearchWord>() : new ObservableCollection<CategorySearchWord>(CategorySearchWords);
}
public ObservableCollection<ProductBase> ProductsObsColl { get; set; }
public ObservableCollection<CategorySearchWord> CategorySearchWordsObsColl { get; set; }
}
Переопределил шаблоны во ViewModel, пара нюансов с конкретизацией сущностей и заработало.