2012-06-09 107 views
10

有一些帖子討論爲ListView.SelectedItems添加數據綁定功能以及不重要​​的代碼量。在我的場景中,我不需要從ViewModel中設置它,只需獲取選定的項目以便對它們執行操作,並且它由命令觸發,因此推送更新也不是必需的。在ViewModel中獲取WPF ListView.SelectedItems

是否有一個簡單的解決方案(就代碼行而言),也許在代碼隱藏?只要ViewViewModel不需要互相引用,我就可以使用代碼隱藏。我認爲這是一個更通用的問題:「虛擬機從視圖點播獲取數據的最佳做法」,但我似乎無法找到任何東西...

回答

23

僅在執行命令時才使用SelectedItems,然後使用CommandParameter並傳入ListView.SelectedItems

<ListBox x:Name="listbox" ItemsSource="{Binding StringList}" SelectionMode="Multiple"/> 
<Button Command="{Binding GetListItemsCommand}" CommandParameter="{Binding SelectedItems, ElementName=listbox}" Content="GetSelectedListBoxItems"/> 
+4

'SelectedItems'(複數)不支持數據綁定。請參閱[此鏈接](http://stackoverflow.com/questions/803216/managing-multiple-selections-with-mvvm)和[此鏈接](http://social.msdn.microsoft.com/forums/en-美國/ WPF /線程/ edd335ea-e5e1-48e1-91a2-793d613f5cc3 /)。它不能作爲'CommandParameter'工作,我總是得到'null',而使用'SelectedItem'(單數)是好的。 –

+0

@ user986080我沒有意識到'SelectedItems'不支持綁定。我從答案中刪除了這個。然而'CommandParameter'確實可行,我已經測試過了,並且能夠列出所選項目。 – evanb

+0

我的XAML示例顯示了一個'ListBox',但我也測試了一個'ListView',並且能夠從命令參數中獲取所選項目。 – evanb

2

我不認爲這是正確的條件考慮'View和ViewModel不需要互相瞭解'; 在MVVM視圖中總是知道ViewModel。

我也遇到過這種情況,我必須在視圖的代碼中訪問ViewModel,然後填充一些數據(如選定的項目),這在使用第三方控件如ListView,DataGrid等時變得必要

如果直接綁定VM屬性是不可能的,那麼我會監聽ListViw.SelectionChanged事件,然後在該事件中更新ViewModels SelectedItems屬性。

更新:

要啓用從視圖VM提取數據,您可以公開對處理視圖特有的功能和視圖模型將有你的瀏覽通過該接口的參考視圖的接口;使用界面仍然保持視圖和ViewModel在很大程度上分離,但我通常不喜歡這個。

MVVM, providing the Association of View to ViewModel

我還是喜歡處理中查看事件的計算策略,並保持更新VM(與所選擇的項目),這樣VM不必擔心執行任何操作之前拉低數據,它只需要使用可用的數據(因爲它將始終被更新)。

+0

對不起,我不清楚。由於不瞭解對方,我的意思是一個不參考另一個。 註冊到'SelectionChanged'事件並不是完全必要的,因爲ViewModel只需要在命令執行時獲取選定的項目。這更像是「虛擬機如何根據需求從視圖中提取數據」。 –

8

這可以通過互動達到觸發如下

  1. 您將需要添加引用

    Microsoft.Expression.Interactions System.Windows。互動

添加下面的xmlns到您的XAML

xmlns:i="http://schemas.microsoft.com/expression//2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 

添加下面只是你的GridView標籤內的代碼

<GridView x:Name="GridName"> 
<i:Interaction.Triggers> 
    <i:EventTrigger EventName="SelectionChanged"> 
     <i:InvokeCommandAction Command="{Binding Datacontext.SelectionChangedCommand, ElementName=YourUserControlName}" CommandParameter="{Binding SelectedItems, ElementName=GridName}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

代碼中的ViewModel財產申報下面

public DelegateCommand<object> SelectionChangedCommand {get;set;} 

內構造或視圖模型的初始化命令,如下

SelectionChangedCommand = new DelegateCommand<object> (items => { 
    var itemList = (items as ObservableCollection<object>).Cast<YourDto>().ToList(); 
} 
+0

我有相同的解決方法, – Mihai

2

我可以向你保證:SelectedItems是一個XAML CommandParameter

確實可綁定了大量挖掘和谷歌搜索後,我終於找到了一個簡單的解決方案到這個共同的問題。

爲了使它工作,你必須遵守所有的規則如下

  1. Ed Ball's suggestion」,你XAML命令綁定,定義CommandParameter屬性之前命令財產。這是一個非常耗時的錯誤。

  2. 確保您的ICommandCanExecute執行方法有對象類型的參數。通過這種方式,您可以防止沉默每當數據綁定時發生轉換異常CommandParameter類型與您的命令方法的參數類型不匹配。

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

例如,您可以發送一個ListView/ListBox的SelectedItems屬性爲您ICommand的方法或列表視圖/列表框它的自我。太好了,不是嗎?

希望它可以防止有人花費的時間我沒有弄清楚鉅額如何接收SelectedItemsCanExecute參數。

0

由於沒有其他答案幫助我(使用SelectedItems作爲CommandParameter總是null),這裏是通用Windows平臺(UWP)應用程序的解決方案。它使用Microsoft.Xaml.InteractivityMicrosoft.Xaml.Interactions.Core

這裏的景觀:

<ListView x:Name="ItemsList"> 
    <Interactivity:Interaction.Behaviors> 
     <Core:EventTriggerBehavior EventName="SelectionChanged"> 
      <Core:InvokeCommandAction Command="{x:Bind ViewModel.SelectedItemsChanged}" /> 
     </Core:EventTriggerBehavior> 
    </Interactivity:Interaction.Behaviors> 
    <!-- content etc. --> 
</ListView> 

這裏的視圖模型(RelayCommand是MVVM光類):

private List<YourType> _selectedItems = new List<YourType>(); 

private RelayCommand<SelectionChangedEventArgs> _selectedItemsChanged; 
public RelayCommand<SelectionChangedEventArgs> SelectedItemsChanged 
{ 
    get 
    { 
     if (_selectedItemsChanged == null) 
      _selectedItemsChanged = new RelayCommand<SelectionChangedEventArgs>((selectionChangedArgs) => 
      { 
       // add a guard here to immediatelly return if you are modifying the original collection from code 

       foreach (var item in selectionChangedArgs.AddedItems) 
        _selectedItems.Add((YourType)item); 

       foreach (var item in selectionChangedArgs.RemovedItems) 
        _selectedItems.Remove((YourType)item); 
      }); 
     return _selectedItemsChanged; 
    } 
} 

請注意,如果您打算以後從原來的集合中刪除項目選擇完成(用戶按下按鈕等),它也會從您的_selectedItems列表中刪除項目!如果你在foreach循環中這樣做,你會得到一個InvalidOperationException。爲了避免這種情況,只需在顯着的地方像添加一個後衛:

if (_deletingItems) 
    return; 

,然後在您例如刪除的項目的方法,這樣做:

_deletingItems = true; 
foreach (var item in _selectedItems) 
    YourOriginalCollection.Remove(item); 
_deletingItems = false;