Удалить выделение из списка через MVVM RelayCommand

StackOverflow https://stackoverflow.com/questions/2803672

  •  25-09-2019
  •  | 
  •  

Вопрос

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

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

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

На мой взгляд, я проводлю мою ремосштабную компанию, как это:

<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);

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

    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);
        }
    }
Это было полезно?

Решение

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

Другие советы

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

 <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);
}

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

1.) Свяжите вашу кнопку Удалить команду в ViewModel.

2..

3.) Убедитесь, что ваша команда в вашем просмотру проходит вдоль аргументов. Вы получите объект, который вы можете бросить как 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
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top