web-dev-qa-db-fra.com

Comment lier la sélection multiple de listview à viewmodel?

J'implémente une vue de liste et un bouton à côté. Je dois pouvoir le faire lorsque je sélectionne plusieurs éléments dans une liste, puis clique sur un bouton, puis les éléments sélectionnés sont placés dans une liste. Mais ma question est, comment puis-je lier les éléments sélectionnés vers le viewmodel? J'ai changé mon mode de sélection en multiple. Mais alors, dois-je juste faire:

SelectedItem={Binding path= selectedItems}

puis faire dans mon modèle de vue une propriété selectedItems, et il définira ces éléments que j'ai sélectionnés? Ou quelle est la bonne solution pour ce faire?

35
Ruben

Ce que vous pouvez faire, c'est que vous pouvez gérer le Button_Click (...) dans votre code-behind. Ensuite, dans cette méthode code-behind, vous pouvez créer une liste d'éléments sélectionnés en itérant sur les éléments sélectionnés de listView.

Puisqu'il est autorisé à accéder au ViewModel à partir de la vue, vous pouvez maintenant appeler une méthode sur votre ViewModel et passer la liste des éléments sélectionnés en tant que paramètre.

Je ne sais pas si cela fonctionnerait également avec les liaisons uniquement, mais ce n'est pas une mauvaise pratique d'utiliser également le code-behind.

Exemple de code:

public void Button_Click(object sender, EventArguments arg)
{
  List<ListViewItem> mySelectedItems = new List<ListViewItem>();

  foreach(ListViewItem item in myListView.SelectedItems)
  {
    mySelectedItems.Add(item);
  }

  ViewModel.SomeMethod(mySelectedItems);
}

MODIFIER

Voici un exemple minimaliste, XAML:

<DataTemplate
            x:Key="CarTemplate"
            DataType="{x:Type Car}">
</DataTemplate>

<ListView x:Name="myListView"
          ItemsSource="{Binding Path=Cars}"
          ItemTemplate="{StaticResource CarTemplate}">
</ListView>

CODE DERRIÈRE:

public void Button_Click(object sender, EventArguments arg)
    {
      List<Car> mySelectedItems = new List<Car>();

      foreach(Car item in myListView.SelectedItems)
      {
        mySelectedItems.Add(item);
      }

      ViewModel.SomeMethod(mySelectedItems);
    }
12
Christian

Comme Doctor l'a déjà souligné, vous pouvez lier SelectedItems à XAML CommandParameter

Après beaucoup de recherches et de recherches sur Google, j'ai finalement trouvé une solution simple à ce problème courant.

Pour le faire fonctionner, vous devez suivre TOUTES les règles suivantes :

  1. Après suggestion d'Ed Ball ', sur votre liaison de données de commande XAML, définissez la propriété CommandParameter BEFORE Commande propriété. C'est un bug qui prend beaucoup de temps.

    enter image description here

  2. Assurez-vous que votre ICommand CanExecute et Les méthodes d'exécution ont un paramètre de type objet . De cette façon, vous pouvez empêcher désactivé les exceptions de cast qui se produisent chaque fois que le type de liaison de données CommandParameter ne correspond pas au type de paramètre de votre méthode de commande.

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
    {
        // Your goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)
    {
        // Your goes here
    }
    

Par exemple, vous pouvez soit vous envoyer une propriété listview/listbox SelectedItems ICommand les méthodes ou la listview/listbox elle-même. Super, non?

J'espère que cela empêchera quelqu'un de passer le temps énorme que j'ai fait pour comprendre comment recevoir SelectedItems en tant que CanExecute paramètre.

37
Julio Nobre

Il est assez difficile de faire cette sélection multiple dans MVVM, car la propriété SelectedItems n'est pas un Dependency Property. Cependant, vous pouvez utiliser certaines astuces. J'ai trouvé cette triologie de billets de blog qui décrivent la question en détail et fournissent des solutions utiles.

J'espère que cela t'aides

22
AbdouMoumen

Si vous utilisez déjà System.Windows.Interactivity et Microsoft.Expression.Interactions, voici une solution de contournement sans autre code/comportement à déconner. Si vous en avez besoin, il peut être téléchargé depuis ici

Cette solution de contournement utilise le déclencheur d'événement d'interactivité et le mécanisme de propriété d'ensemble d'interactions dans les assemblys ci-dessus.

Déclaration d'espace de noms supplémentaire en XAML

xmlns:i="clr-namespace:System.Windows.Interactivity;Assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.Microsoft.com/expression/2010/interactions"

XAML:

<ListView Name="MyListView" ItemsSource="{Binding ModelList}" DisplayMemberPath="Name"  Grid.Column="0">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
      <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedItems" Value="{Binding Path=SelectedItems, ElementName=MyListView}"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</ListView>

Voir le modèle:

public class ModelListViewModel
{
  public ObservableCollection<Model> ModelList { get; set; }
  public ObservableCollection<Model> SelectedModels { get; set; }

  public ModelListViewModel() {
    ModelList = new ObservableCollection<Model>();
    SelectedModels = new ObservableCollection<Model>();
  }

  public System.Collections.IList SelectedItems {
    get {
      return SelectedModels;
    }
    set {
      SelectedModels.Clear();
      foreach (Model model in value) {
        SelectedModels.Add(model);
      }
    }
  }
}

Dans l'exemple ci-dessus, votre ViewModel récupérera les éléments sélectionnés chaque fois que la sélection sur ListView a changé.

13
techhero

Malheureusement, SelectedItems est une propriété non lisible en lecture seule.

J'ai trouvé beaucoup d'aide dans cet article Comment lier des données à une propriété SelectedItems dans WPF

6
Dummy01

Vous ne pouvez pas lier, mais vous pouvez envoyer à Command en tant que CommandParameter.

4
Doctor

Si vous utilisez Metro/WinRT vous voudrez peut-être regarder le WinRTXXAMLToolkit car il offre une propriété de dépendance SelectedItems liable comme l'une de ses extensions.

3
technicalflaw

J'ai fait une solution pour cela, pour moi, c'était assez simple.

<ListBox ItemsSource="{Binding ListOfModel}" x:Name="ModelList"
                                SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="SelectionChanged">
                                    <i:InvokeCommandAction Command="{Binding ExecuteListBoxSelectionChange}" CommandParameter="{Binding ElementName=ModelList}">
                                    </i:InvokeCommandAction>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </ListBox>

Puis dans le viewmodel:

public ICommand ExecuteListBoxSelectionChange { get; private set; }
ExecuteListBoxSelectionChange = DelegatingCommand<ListBox>.For(ListBoxSelectionChnageEvent).AlwaysEnabled();

SelectedModels est la liste où je voulais que la sélection soit remplie.

    private void ListBoxSelectionChnageEvent(ListBox modelListBox)
    {
        List<ModelInfo> tempModelInfo = new List<ModelInfo>();
         foreach(ModelInfo a in modelListBox.SelectedItems)
             tempModelInfo.Add(a);

         SelectedModels = tempModelInfo;
    }
0
Manas S