Question

J'ai une liste d'éléments dans une zone de liste WPF. Je veux permettre à l'utilisateur de sélectionner plusieurs de ces éléments et cliquez sur un bouton Supprimer pour supprimer 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; }

À mon avis, je câbler mon RemoveTagsCommand comme ceci:

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

Mon constructeur ViewModel met en place une instance de la commande:

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

Ma mise en œuvre actuelle de RemoveTags se sent maladroit, avec des moulages et la copie. Y at-il une meilleure façon de mettre en œuvre ce?

    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);
        }
    }
Était-ce utile?

La solution

Cela semble assez propre pour moi, bien que vous pourriez être en mesure de lier SelectedItems à une propriété sur votre machine virtuelle à l'aide Mode=OneWayToSource puis utilisez la propriété de collection liée de RemoveTags.
Je ne suis pas tout à fait sûr, mais vous pouvez être capable d'utiliser une collection IList fortement typée dans ce cas.

Autres conseils

J'utilise le ItemContainerStyle sur le ListBox pour lier les éléments de propriété IsSelected à un drapeau dans le modèle (non voir le modèle), par exemple:.

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

Ensuite, vous n'avez pas à vous soucier de quel argument vous passez à votre commande. De plus, dans mon expérience quand il est simple pour un objet dans un modèle en vue de savoir que l'utilisateur a sélectionné, vous trouverez d'autres utilisations pour ces informations.

Le code de la commande serait quelque chose comme:

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

Pourquoi ne pas vous spécifiez l'argument type de RelayCommand être un List<Tag>, puisque c'est ce que vous allez obtenir de toute façon? Il n'y a pas de point en spécifiant un type plus générique que parce que le gestionnaire exécuté est codé en dur de travailler avec une liste d'objets Tag. Puisque vous avez déjà fait la dépendance là-bas, vous pourriez aussi bien le faire sur l'argument de type, aussi bien. Ensuite, votre gestionnaire exécuté aura pas besoin de fonte ou de copie.

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

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

3.) Assurez-vous que votre commande dans votre ViewModel passe le long des arguments. Vous obtenez un objet que vous pouvez lancer en tant IList.

Voici un exemple simple, cela devrait vous aider à configurer 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
}

Hope this helps!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top