Comment lier plusieurs sélections de listview à viewmodel?
J'implémente un listview, et un bouton à côté. J'ai de pouvoir que lorsque je sélectionne plusieurs éléments dans une liste, puis cliquez sur un bouton, puis les éléments sélectionnés sont mis dans une liste. Mais ma question est , comment puis-je lier les éléments sélectionnés vers le viewmodel? J'ai changé mon selectionmode à plusieurs. Mais alors, dois-je juste faire:
SelectedItem={Binding path= selectedItems}
Et puis faire dans mon viewmodel une propriété selectedItems, et il va définir ces éléments que j'ai sélectionnés? Ou qu'est-ce que le droit solution pour ce faire?
9 réponses
Ce que vous pouvez faire est que vous pouvez gérer le Button_Click(...) dans votre code-derrière. Ensuite, dans cette méthode de 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.
Comme il est autorisé à accéder au ViewModel depuis 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 suis pas sûr si cela fonctionnerait aussi avec des liaisons seulement, mais ce n'est pas une mauvaise pratique d'utiliser code-behind as Bien.
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);
}
Comme Médecin l'a déjà souligné, vous pouvez lier SelectedItems XAML CommandParameter
Après beaucoup de creuser et de googler, j'ai finalement trouvé une solution simple à ce problème commun.
Pour le faire fonctionner, vous devez , suivre TOUTES les règles suivantes:
-
Suivant la suggestion de Ed Ball ', sur votre liaison de données de commande XAML, définissez CommandParameterpropriété avant Commande propriété. Ce un bug très chronophage.
-
Assurez-vous que votre ICommand's CanExecute et Exécuter méthodes ont un paramètre de object type. De cette façon, vous pouvez empêcher les exceptions silenced cast qui se produisent lorsque le type databinding 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 envoyer la propriété SelectedItems d'une listview/listbox pour vous ICommand méthodes ou le listview / listbox lui-même. Grande, n'est-ce pas?
Espère qu'il empêche quelqu'un de dépenser de l'énorme quantité de temps que j'ai fait pour comprendre comment recevoir SelectedItems, comme CanExecute paramètre.
Il est un peu difficile de faire cette sélection multiple dans MVVM, car la propriété SelectedItems
n'est pas un Dependency Property
. Cependant, il y a quelques astuces que vous pouvez utiliser. J'ai trouvé cette triologie de messages de blog qui décrivent la question dans certains détails et fournissent des solutions utiles.
J'espère que cela aide
Si vous utilisez le système.Windows.Interactivité et Microsoft.Expression.Interactions déjà, voici une solution de contournement sans autre code / comportement à déranger. Si vous en avez besoin, il peut être téléchargé à partir de ici
Cette solution de contournement utilise le mécanisme de propriété interactivity event trigger et interactions set dans les assemblys ci-dessus.
Déclaration d'espace de noms supplémentaire dans 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>
Vue 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 sélectionnera les éléments sélectionnés Chaque fois que la sélection sur ListView a changé.
Malheureusement, SelectedItems est une propriété non bindable en lecture seule.
J'ai trouvé beaucoup d'aide de cet article Comment Databind à une propriété SelectedItems dans WPF
Vous ne pouvez pas lier, mais vous pouvez envoyer à la commande en tant que CommandParameter.
Si vous utilisez Metro/WinRT
vous pouvez regarder le WinRTXXAMLToolkit car il offre une bindable SelectedItems
la propriété de dépendance comme l'une de ses extensions.
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;
}
Comme une légère variation sur le post de Christian, j'ai implémenté un code similaire en utilisant le ListView.Événement SelectionChanged. Au lieu d'appeler une méthode sur ViewModel, j'ai défini une propriété appelée SelectedItems:
public void ListView_SelectionChanged( object s, SelectionChangedEventArgs e ) {
List<Car> mySelectedItems = new List<Car>();
foreach( Car item in myListView.SelectedItems )
mySelectedItems.Add(item);
ViewModel.SelectedItems = mySelectedItems;
}
De cette façon, ViewModel.SelectedItems est disponible pour toute commande que vous pourriez avoir dans votre ViewModel et il peut être utilisé pour la liaison de données (si vous le transformez en ObservableCollection).