Удалить SelectedItems из ListBox через MVVM RelayCommand

108
10

У меня есть список элементов в ListBox WPF. Я хочу разрешить пользователю выбирать несколько из этих элементов и нажать кнопку "Удалить", чтобы исключить эти элементы из списка.


Используя шаблон MVVM RelayCommand, я создал команду со следующей подписью:


public RelayCommand<IList> RemoveTagsCommand { get; private set; }

В моем представлении я подключу свой RemoveTagsCommand следующим образом:


<DockPanel>
<Button DockPanel.Dock="Right" Command="{Binding RemoveTagsCommand}" CommandParameter="{Binding ElementName=TagList, Path=SelectedItems}">Remove tags</Button>
<ListBox x:Name="TagList" ItemsSource="{Binding Tags}" SelectionMode="Extended">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.Resources>
<DataTemplate DataType="{x:Type Model:Tag}">
...
</DataTemplate>
</ListBox.Resources>
</ListBox>
</DockPanel>

Мой конструктор ViewModel устанавливает экземпляр команды:


RemoveTagsCommand = new RelayCommand<IList>(RemoveTags, CanRemoveTags);

Моя текущая реализация RemoveTags кажется неуклюжей, с приложением и копированием. Есть ли лучший способ реализовать это?


    public void RemoveTags(IList toRemove)
{
var collection = toRemove.Cast<Tag>();
List<Tag> copy = new List<Tag>(collection);

foreach (Tag tag in copy)
{
Tags.Remove(tag);
}
}

спросил(а) 2021-01-25T18:56:23+03:00 4 месяца, 4 недели назад
1
Решение
99

Я бы использовал ItemContainerStyle в ListBox для привязки свойства items IsSelected к флагу в Model (не View Model), например:


 <ListBox.ItemContainerStyle> 
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.ItemContainerStyle>

Тогда вам не нужно беспокоиться о том, какой аргумент вы передаете своей команде. Кроме того, по моему опыту, когда для объекта в модели представления просто знать, что пользователь выбрал его, вы найдете другое использование этой информации.

Код в команде будет выглядеть примерно так:


foreach (Tag t in Tags.Where(x => x.IsSelected).ToList())
{
Tags.Remove(t);
}

ответил(а) 2021-01-25T18:56:23+03:00 4 месяца, 4 недели назад
78

Это выглядит довольно чистым для меня, хотя вы можете привязать SelectedItems к свойству на вашей виртуальной машине с помощью Mode=OneWayToSource, а затем использовать свойство bound collection из RemoveTags.
Я не полностью уверен, но в этом случае вы можете использовать строго типизированную коллекцию IList.

ответил(а) 2021-01-25T18:56:23+03:00 4 месяца, 4 недели назад
46

Почему бы вам не указать аргумент типа RelayCommand как List<Tag>, так как это то, что вы все равно получите? Нет смысла указывать более общий тип, чем тот, потому что исполняемый обработчик жестко закодирован для работы со списком объектов Tag. Поскольку вы уже создали зависимость там, вы также можете сделать это и в аргументе типа. Тогда вашему исполняемому обработчику не понадобится какое-либо копирование или копирование.

ответил(а) 2021-01-25T18:56:23+03:00 4 месяца, 4 недели назад
45

1.) Привяжите кнопку "Удалить" команду "Command" в вашей модели ViewModel.


2.) Когда вы настраиваете привязку, используйте CommandParameter, чтобы взять Selecteditems из вашего ListBox, указав имя ListBox и используя ElementName = NameOfListBox, Path = SelectedItems


3.) Убедитесь, что ваша команда в вашей модели ViewModel проходит по аргументам. Вы получите объект, который вы можете использовать как IList.


Ниже приведен простой пример: это поможет вам настроить структуру.


В представлении:


<Button Command="{Binding CommandInViewModelForRemove}"
CommandParameter="{Binding ElementName=blah,Path=SelectedItems}"

<ListBox x:Name="blah" .... />


В ViewModel:


public ViewModel(){
RemoveCommand = new RelayCommand<object>(Remove, CanRemove);
}

private void Remove(object selectedItems){
var list = (IList)selectedItems;
//do some work, cast to view models that represent list items, etc
}


Надеюсь, это поможет!

ответил(а) 2021-01-25T18:56:23+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема