.net 正在ViewModel中获取WPF ListView.SelectedItems

.net 正在ViewModel中获取WPF ListView.SelectedItems,.net,wpf,listview,data-binding,mvvm,.net,Wpf,Listview,Data Binding,Mvvm,有一些帖子讨论了为ListView添加数据绑定功能。在我的场景中,我不需要从ViewModel中设置它,只需要获取所选项目以对其执行操作,它由命令触发,因此也不需要推送更新 是否有一个简单的解决方案(在代码行方面),可能是在代码隐藏中?只要View和ViewModel不需要相互引用,我就可以使用代码隐藏。我认为这是一个更一般的问题:“VM从按需视图获取数据的最佳实践”,但我似乎什么也找不到……/P> < P>我认为认为“强->视图和视图模型不需要互相了解< /强>”是正确的条件;在MVVM视图中

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


是否有一个简单的解决方案(在代码行方面),可能是在代码隐藏中?只要
View
ViewModel
不需要相互引用,我就可以使用代码隐藏。我认为这是一个更一般的问题:“VM从按需视图获取数据的最佳实践”,但我似乎什么也找不到……/P> < P>我认为认为“强->视图和视图模型不需要互相了解< /强>”是正确的条件;在MVVM视图中,始终了解ViewModel

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

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

更新:

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


我仍然更喜欢在视图中处理事件并保持VM更新的方法(使用所选项目),这样VM在执行任何操作之前不必担心提取数据,它只需要使用可用的数据(因为这些数据总是更新的).

要仅在执行命令时获取
SelectedItems
,请使用
CommandParameter
并传入
列表视图。选择editems

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

这可以通过如下交互触发器实现

SelectionChangedCommand = new DelegateCommand<object> (items => {
   var itemList = (items as ObservableCollection<object>).Cast<YourDto>().ToList();
}
  • 您需要添加对的引用

    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;}
    
    public DelegateCommand SelectionChangedCommand{get;set;}
    
    在Viewmodel的构造函数中初始化命令,如下所示

    SelectionChangedCommand = new DelegateCommand<object> (items => {
       var itemList = (items as ObservableCollection<object>).Cast<YourDto>().ToList();
    }
    
    SelectionChangedCommand=newdelegateCommand(项=>{
    var itemList=(项目作为ObservableCollection.Cast().ToList();
    }
    
    我可以向您保证:SelectedItems确实可以绑定为XAMLCommandParameter

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

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

  • 在XAML命令数据绑定之后,在命令属性之前定义命令参数属性。这是一个非常耗时的错误

  • 确保您的ICommandCanExecuteExecute方法具有object类型的参数。这样可以防止在数据绑定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参数来接收。

    因为其他答案对我都没有帮助(使用
    SelectedItems
    作为
    CommandParameter
    总是
    null
    ),这是一个针对通用Windows平台(UWP)应用程序的解决方案。它使用
    Microsoft.Xaml.Interactivity
    Microsoft.Xaml.interactiviations.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>
    
    请注意,如果您要在选择完成后从原始集合中删除项目(用户按下按钮等),它还将从您的
    \u selectedItems
    列表中删除项目!如果您在foreach循环中执行此操作,您将获得
    无效操作异常
    。要避免此情况,只需在标记的位置添加一个防护,如:

    if (_deletingItems)
        return;
    
    然后,在您删除项目的方法中,执行以下操作:

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

    抱歉,我不清楚。互不了解意味着一方不引用另一方。注册到
    SelectionChanged
    事件也不是完全必要的,因为ViewModel只需要在执行命令时获取所选项目。这更像是“VM如何根据需要从视图中提取数据”。
    SelectedItems
    (复数)不支持数据绑定。请参阅和。它也不作为
    CommandParameter
    工作,在使用
    SelectedItem
    (单数)时,我总是得到
    null
    很好。@user986080我没有意识到
    SelectedItems
    不支持绑定。我从答案中删除了它。但是
    CommandParameter
    确实有效,我已经测试了它,并且能够查看所选项目的列表。我的XAML示例显示了一个
    列表框
    ,但我也测试了一个
    列表视图
    ,并且可以从命令参数中获取所选项目。我想我正在点击,这是一个很麻烦的解决方法。但理想情况下,您的答案是正确的。非常感谢您提供此CommandParameter解决方案。对我来说效果非常好