2 votes

Suppression des éléments sélectionnés d'une ListBox via MVVM RelayCommand

J'ai une liste d'éléments dans une ListBox WPF. Je veux permettre à l'utilisateur de sélectionner plusieurs de ces éléments et de cliquer sur un bouton Supprimer pour éliminer ces éléments de la liste.

En utilisant le modèle MVVM RelayCommand, j'ai créé une commande avec la signature suivante :

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

Dans ma vue, j'ai câblé ma commande RemoveTagsCommand de la façon suivante :

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

Le constructeur de mon ViewModel crée une instance de la commande :

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

Mon implémentation actuelle de RemoveTags est maladroite, avec des castings et des copies. Existe-t-il une meilleure façon de l'implémenter ?

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

4voto

Robert Rossney Points 43767

J'utiliserais le ItemContainerStyle en el ListBox pour lier les éléments IsSelected à un drapeau dans le modèle (pas dans le modèle de vue), par exemple :

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

Vous n'avez donc pas à vous soucier de l'argument que vous transmettez à votre commande. De plus, d'après mon expérience, lorsqu'il est simple pour un objet dans un modèle de vue de savoir que l'utilisateur l'a sélectionné, vous trouvez d'autres utilisations pour cette information.

Le code dans la commande serait quelque chose comme :

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

3voto

Dan Bryant Points 19021

Cela me semble assez propre, mais vous pourriez peut-être lier SelectedItems à une propriété de votre VM en utilisant Mode=OneWayToSource et ensuite utiliser la propriété de collection liée de RemoveTags .
Je ne suis pas tout à fait sûr, mais vous pouvez peut-être utiliser une collection IList fortement typée dans ce cas.

0voto

Charlie Points 9880

Pourquoi ne pas spécifier l'argument de type de la fonction RelayCommand pour être un List<Tag> puisque c'est ce que vous obtiendrez de toute façon ? Il est inutile de spécifier un type plus générique que cela, car le gestionnaire exécuté est codé en dur pour travailler avec une liste de Tag objets. Puisque vous avez déjà créé la dépendance à cet endroit, vous pouvez également la créer dans l'argument de type. Ainsi, votre gestionnaire exécuté n'aura pas besoin de cast ou de copie.

0voto

Jimmy Lyke Points 145

1.) Liez votre bouton Supprimer à une commande dans votre ViewModel.

2.) Lorsque vous configurez votre liaison, utilisez un CommandParameter pour prendre les Selecteditems de votre ListBox en donnant un nom à votre ListBox et en utilisant ElementName=NameOfListBox, Path=SelectedItems.

3.) Assurez-vous que votre commande dans votre ViewModel transmet les arguments. Vous obtiendrez un objet que vous pourrez convertir en IList.

Vous trouverez ci-dessous un exemple simple, qui devrait vous aider à mettre en place votre structure.

Dans la vue :

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

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

Dans le 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
}

J'espère que cela vous aidera !

-1voto

Voss Points 1

Je n'essaie pas de détourner ce sujet, mais mon SelectedItems.Count est toujours égal à ZERO.

J'ai trouvé ce fil de Laurent (à la fin du fil) : http://geekswithblogs.net/lbugnion/archive/2010/05/19/handling-datagrid.selecteditems-in-an-mvvm-friendly-manner.aspx

Merci, voss.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X