使用MVVM管理多个选择

Pau*_*der 59 .net c# data-binding mvvm

在我学习MVVM的过程中,我已经建立了对WPF和ViewModel模式的一些基本理解.我在提供列表时使用以下抽象,并且对单个选定项目感兴趣.

public ObservableCollection<OrderViewModel> Orders { get; private set; }
public ICollectionView OrdersView
{
    get
    {
        if( _ordersView == null )
            _ordersView = CollectionViewSource.GetDefaultView( Orders );
        return _ordersView;
    }
}
private ICollectionView _ordersView;

public OrderViewModel CurrentOrder 
{ 
    get { return OrdersView.CurrentItem as OrderViewModel; } 
    set { OrdersView.MoveCurrentTo( value ); } 
}
Run Code Online (Sandbox Code Playgroud)

然后,我可以将OrdersView与支持排序和过滤绑定到WPF中的列表:

<ListView ItemsSource="{Binding Path=OrdersView}" 
          IsSynchronizedWithCurrentItem="True">
Run Code Online (Sandbox Code Playgroud)

这对单选视图非常有效.但我还想支持视图中的多个选择,并让模型绑定到所选项的列表.

如何将ListView.SelectedItems绑定到ViewModel上的backer属性?

Jos*_*h G 94

IsSelected属性添加到您的子ViewModel(OrderViewModel在您的情况下):

public bool IsSelected { get; set; }
Run Code Online (Sandbox Code Playgroud)

将容器上的selected属性绑定到此(在本例中为ListBox):

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
    </Style>
</ListBox.ItemContainerStyle>
Run Code Online (Sandbox Code Playgroud)

IsSelected 已更新以匹配容器上的相应字段.

您可以通过执行以下操作在视图模型中获取所选子项:

public IEnumerable<OrderViewModel> SelectedOrders
{
    get { return Orders.Where(o => o.IsSelected); }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,在ListBox中使用VirtualizingStackPanel时,此解决方案无法正常工作(这是默认设置).这篇文章的更多信息:http://stackoverflow.com/questions/1273659/virtualizingstackpanel-mvvm-multiple-selection (29认同)
  • 如果您使用的是虚拟化面板,则无法使用此方法.解决方法是在视图后面的代码中处理SelectionChanged事件.然后很容易通过代码将选择传递给VM ...事件处理程序为您提供了新选择和未选中的所有项目. (4认同)
  • 接得好.感谢更新.对于单选,最好的解决方案是ICollectionView.Microsoft需要创建支持多选的ICollectionView接口. (3认同)

Jul*_*bre 12

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

这个常见问题有一个简单的解决方案; 要使其工作,您必须遵守以下所有规则:

  1. 埃德球的建议,你的XAML命令绑定,定义CommandParameter属性之前Command属性.这是一个非常耗时的错误.

    在此输入图像描述

  2. 确保你ICommandCanExecuteExecute方法有一个类型的参数object.这样就可以防止沉默的发生每当数据绑定的转换异常CommandParameter类型不匹配Command方法的参数类型:

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)  
    {
         // Your code goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)  
    {
        // Your code goes here
    }
    
    Run Code Online (Sandbox Code Playgroud)

例如,您可以将ListView/ ListBoxSelectedItems属性发送到您的ICommand方法或ListView/ ListBox本身.太棒了,不是吗?

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

  • 我只是尝试使用DataGrid,以这种方式使用SelectedItems属性我发现如果SelectedItems(即它没有反映选择的当前状态),则使用_previous_值调用CanExecute.对于其他控件可能有所不同,但在这种情况下证明是无用的. (2认同)
  • 很好,非常适合4.5.2的listview.要添加的是我还使用了Prism的DelegateCommand来执行Execute和CanExecute.so:`ICommand btnCommand = new DelegateCommand <object>(Execute,CanExecute);` (2认同)