15

有一些帖子讨论了为ListView.SelectedItems大量代码添加数据绑定能力。在我的场景中,我不需要从 中设置它ViewModel,只需获取选定的项目以便对它们执行操作,它是由命令触发的,因此也不需要推送更新。

是否有一个简单的解决方案(就代码行而言),也许在代码隐藏中?只要不需要相互引用View,我就可以使用代码隐藏。ViewModel我认为这是一个更通用的问题:“ VM 从按需查看数据的最佳实践”,但我似乎找不到任何东西......

4

5 回答 5

28

要获得SelectedItems仅在执行命令时,请使用CommandParameter并传入ListView.SelectedItems.

<ListBox x:Name="listbox" ItemsSource="{Binding StringList}" SelectionMode="Multiple"/>
<Button Command="{Binding GetListItemsCommand}" CommandParameter="{Binding SelectedItems, ElementName=listbox}" Content="GetSelectedListBoxItems"/>
于 2012-06-12T23:35:24.250 回答
11

这可以使用交互触发器来实现,如下所示

  1. 您将需要添加参考

    Microsoft.Expression.Interactions System.Windows.Interactivity

将以下 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;}

在 Viewmodel 的构造函数中初始化命令如下

SelectionChangedCommand = new DelegateCommand<object> (items => {
   var itemList = (items as ObservableCollection<object>).Cast<YourDto>().ToList();
}
于 2013-08-15T12:45:10.500 回答
4

我认为考虑“视图和视图模型不需要相互了解”是不正确的条件;在 MVVM 视图中总是知道 ViewModel。

我也遇到过这种情况,我必须在后面的视图代码中访问 ViewModel,然后填充一些数据(如所选项目),这在使用 ListView、DataGrid 等第三方控件时变得很有必要。

如果无法直接绑定 VM 属性,那么我将监听 ListViw.SelectionChanged 事件,然后在该事件中更新我的 ViewModels SelectedItems 属性。

更新:

要启用 VM 从视图中提取数据,您可以在视图上公开一个处理视图特定功能的接口,并且 ViewModel 将通过该接口引用您的视图;使用接口仍然使 View 和 ViewModel 在很大程度上解耦,但我一般不喜欢这样。

MVVM,提供 View 到 ViewModel 的关联

我仍然更喜欢在 View 中处理事件并保持 VM 更新(使用所选项目)的方法,这样 VM 在执行任何操作之前不必担心提取数据,它只需要使用可用的数据(因为那将永远更新一个)。

于 2012-06-10T06:03:44.533 回答
3

我可以向您保证:SelectedItems确实可以绑定为 XAML CommandParameter

经过大量的挖掘和谷歌搜索,我终于找到了解决这个常见问题的简单方法。

要使其正常工作,您必须遵循以下所有规则

  1. 按照Ed Ball 的建议,在您的 XAML 命令数据绑定上,在Command属性之前定义CommandParameter属性。这是一个非常耗时的错误。

  2. 确保您的ICommandCanExecuteExecute方法具有对象类型的参数。这样,您可以防止数据绑定CommandParameter类型与命令方法的参数类型不匹配时发生的静默强制转换异常。

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

例如,您可以将 listview/listbox 的SelectedItems属性发送给您的ICommand方法或它自己的 listview/listbox。太好了,不是吗?

希望它可以防止有人花费大量时间来弄清楚如何接收SelectedItems作为CanExecute参数。

于 2014-09-22T02:06:55.140 回答
0

由于没有其他答案对我有帮助(一如既往地使用SelectedItemsCommandParameternull因此这是通用 Windows 平台 (UWP) 应用程序的解决方案。它使用Microsoft.Xaml.Interactivity和工作Microsoft.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>

这是 ViewModel(RelayCommand是 MVVM Light 的一个类):

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;
于 2016-04-05T20:35:22.957 回答