2009-08-13 12 views
22

ich ein Auswahlmuster ähnlich dem in this post beschrieben implementiert haben eine Ansichtsmodell mit dem IsSelected Wert zu speichern, und durch die ListViewItem.IsSelected auf die Ansichtsmodell IsSelected Bindung:VirtualizingStackPanel + MVVM + Mehrfachauswahl

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

Es funktioniert im Allgemeinen, aber ich stoße auf ein ernstes Problem. Wenn Sie die a VirtualizingStackPanel als Panel in der Listenansicht verwenden, werden nur die sichtbaren ListViewItem erstellt. Wenn ich "Strg + A" verwende, um alle Elemente auszuwählen, oder eine Verknüpfungskombination wie "Umschalt + Strg + Ende" für das erste Element verwenden, werden alle Elemente ausgewählt, aber für nicht sichtbare Elemente erhält das ViewModel nicht seine IsSelected auf wahr gesetzt. Das ist logisch, denn wenn die ListViewItem nicht erstellt werden, kann die Bindung nicht funktionieren.

Jeder hatte das gleiche Problem und fand eine Lösung (abgesehen davon, dass kein VirtualizingStackPanel verwendet wurde)?

+0

diese komplette Lösung für dieses Problem Versuchen: http://Stackoverflow.com/a/29545790 – nvkokorin

Antwort

28

Ich habe einen anderen Weg gefunden, die Auswahl im MVVM-Muster zu handhaben, was mein Problem gelöst hat. Anstatt die Auswahl im Ansichtsmodell beizubehalten, wird die Auswahl aus der ListView/ListBox abgerufen und als Parameter an das Command übergeben. Alles in XAML getan:

<ListView 
    x:Name="_items" 
    ItemsSource="{Binding Items}" ... /> 

<Button 
    Content="Remove Selected" 
    Command="{Binding RemoveSelectedItemsCommand}" 
    CommandParameter="{Binding ElementName=_items, Path=SelectedItems}"/> 

in meinem Viewmodel:

private void RemoveSelection(object parameter) 
{ 
    IList selection = (IList)parameter; 
    ... 
} 
+5

Ich mag diesen Ansatz, aber Sie können nicht Elemente auf diese Weise programmatisch aus dem Viewmodel auswählen. –

+1

Es wird auch nicht funktionieren, wenn Listview und die Schaltfläche in verschiedenen Benutzersteuerbereich sind. –

1

Neben nicht VirtualizingStackPanel verwenden, das einzige, was ich denken kann, ist diese Tastenkombinationen zu erfassen und haben Methoden für einen bestimmten Bereich Ihrer ViewModel Artikel zu modifizieren, so dass ihre IsSelected Eigenschaft auf True gesetzt (zB SelectAll(), SelectFromCurrentToEnd()). Grundsätzlich Umgehung der Binding auf ListViewItem zur Steuerung der Auswahl für solche Fälle.

+2

Vergessen Sie nicht die verschiedenen Möglichkeiten, wie dies mit der Tastatur oder der Maus passieren kann! Strg + A, Umschalt + Ende, Umschalt + Home, und Sie können mit gedrückter Umschalttaste auf einen beliebigen Bereich mit der Maus klicken; All diese Dinge können das gleiche Problem verursachen. – Qwertie

3

In meinem Fall endete ich diese Lösung, indem Sie eine ListBoxEx Klasse von ListBox ableiten, und dem Hinzufügen von Code Auswahl Änderungen zu reagieren, die Durchsetzung der Auswahlzustand auf den Punkt Ansicht Modelle:

private readonly List<IListItemViewModelBase> selectedItems = new List<IListItemViewModelBase>(); 

protected override void OnSelectionChanged(SelectionChangedEventArgs e) 
{ 
    base.OnSelectionChanged(e); 

    bool isVirtualizing = VirtualizingStackPanel.GetIsVirtualizing(this); 
    bool isMultiSelect = (SelectionMode != SelectionMode.Single); 

    if (isVirtualizing && isMultiSelect) 
    { 
     var newSelectedItems = SelectedItems.Cast<IListItemViewModelBase>(); 

     foreach (var deselectedItem in this.selectedItems.Except(newSelectedItems)) 
     { 
      deselectedItem.IsSelected = false; 
     } 

     this.selectedItems.Clear(); 
     this.selectedItems.AddRange(newSelectedItems); 

     foreach (var newlySelectedItem in this.selectedItems) 
     { 
      newlySelectedItem.IsSelected = true; 
     } 
    } 
}