2009-08-13 12 views
22

I wprowadziły wzór selekcji podobną do tej opisanej w this post użyciu ViewModel do przechowywania wartości IsSelected, a przez związanie ListViewItem.IsSelected do ViewModel IsSelected:VirtualizingStackPanel + MVVM + wybór wielokrotny

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

To działa ogólnie, ale napotykam na poważny problem. Za pomocą panelu VirtualizingStackPanel jako panelu w widoku listy tworzone są tylko widoczne ListViewItem. Jeśli użyję "Ctrl + A", aby wybrać wszystkie elementy, lub używając kombinacji skrótów takich "Shift + Ctrl + End" na pierwszym elemencie, wszystkie elementy zostaną wybrane, ale w przypadku niewidocznych elementów ViewModel nie zostanie usunięty z IsSelected ustawione na true. Jest to logiczne, ponieważ jeśli nie zostaną utworzone ListViewItem, powiązanie nie będzie działać.

Ktoś doświadczył tego samego problemu i znalazł rozwiązanie (oprócz nieużywania VirtualizingStackPanel)?

+0

Spróbuj kompletne rozwiązanie dla tego problemu: http://stackoverflow.com/a/29545790 – nvkokorin

Odpowiedz

28

Znalazłem inny sposób obsługi zaznaczenia w schemacie MVVM, który rozwiązał mój problem. Zamiast utrzymywania selekcji w viewmodel, selekcja jest pobierana z ListView/ListBox i przekazywana jako parametr do Command. Wszystko odbywa się w XAML:

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

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

w moim ViewModel:

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

Podoba mi się to podejście, ale nie można wybrać elementów programowo z viewmodel w ten sposób. –

+1

To również nie zadziała, jeśli Listview i przycisk mają inny zakres kontroli użytkownika. –

1

Oprócz nieużywania VirtualizingStackPanel, jedyne co mogę myśleć o to, aby uchwycić te skróty klawiszowe i mieć metody modyfikowania pewien zakres swojego ViewModel przedmioty tak, że ich IsSelected właściwość jest ustawiona na True (np SelectAll(), SelectFromCurrentToEnd()). Zasadniczo omijanie Binding pod numerem ListViewItem w celu kontrolowania wyboru dla takich przypadków.

+2

Nie zapomnij o różnych sposobach, w jakie może się to dziać za pomocą klawiatury lub myszy! Ctrl + A, Shift + End, Shift + Home i możesz naciskać klawisz Shift-Click w dowolnym zakresie za pomocą myszy; wszystkie te rzeczy mogą powodować ten sam problem. – Qwertie

3

W moim przypadku skończyło się na rozwiązywaniu tego wyprowadzając klasę ListBoxEx z pola listy i dodanie kodu do reagowania na zmiany wyboru, egzekwowanie stan wybór na widoku pozycja modeli:

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