2009-08-13 39 views
22

我已經實現類似於使用視圖模型來存儲IsSelected值在this post描述的一個的選擇模式,以及由ListViewItem.IsSelected結合視圖模型IsSelected:VirtualizingStackPanel + MVVM +多個選擇

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

它的工作原理總的來說,但我遇到了嚴重的問題。通過在列表視圖中使用a VirtualizingStackPanel作爲面板,將只創建可見的ListViewItem。如果我使用「Ctrl + A」選擇所有項目,或者在第一個項目上使用快捷鍵組合(如「Shift + Ctrl + End」),則所有項目都會被選中,但對於不可見項目,ViewModel不會獲得其IsSelected設置爲true。這是合乎邏輯的,因爲如果未創建ListViewItem,則綁定無法工作。

有人遇到同樣的問題,並找到了解決方案(除了不使用VirtualizingStackPanel)?

+0

嘗試針對此問題的完整解決方案: http://stackoverflow.com/a/29545790 – nvkokorin 2015-04-09 18:17:59

回答

28

我發現了另一種處理MVVM模式中選擇的方式,它解決了我的問題。而不是維護視圖模型中的選擇,從ListView/ListBox中檢索選擇,並將其作爲參數傳遞給Command。在XAML全部完成:

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

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

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

我喜歡這種方法,但是您無法以這種方式通過編程方式從視圖模型中選擇項目。 – 2011-01-13 15:07:48

+1

如果Listview和按鈕處於不同的用戶控制範圍內,它將不起作用。 – 2014-09-15 23:37:35

1
從沒有使用 VirtualizingStackPanel

除此之外,我能想到的唯一的事情就是要捕捉那些鍵盤快捷鍵和使他們的IsSelected屬性設置爲True(例如,SelectAll()SelectFromCurrentToEnd()有修改一定範圍內的ViewModel項目的方法)。基本上繞過 ListViewItem控制這種情況下的選擇。

+2

不要忘記這可能發生在鍵盤或鼠標上的所有不同的方式! Ctrl + A,Shift + End,Shift + Home,您可以按住Shift鍵單擊鼠標的任意範圍;所有這些都會導致同樣的問題。 – Qwertie 2011-11-10 23:11:50

3

就我而言,我最終通過派生從Control一個ListBoxEx類,並添加代碼以選擇的變化做出反應解決此,執行在項目視圖模型的選擇狀態:

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