C# 使用 MVVM 管理多个选择

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/803216/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 01:49:07  来源:igfitidea点击:

Managing multiple selections with MVVM

c#.netdata-bindingmvvm

提问by Paul Alexander

On my journey to learning MVVM I've established some basic understanding of WPF and the ViewModel pattern. I'm using the following abstraction when providing a list and am interested in a single selected item.

在学习 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 ); } 
}

I can then bind the OrdersView along with supporting sorting and filtering to a list in WPF:

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

<ListView ItemsSource="{Binding Path=OrdersView}" 
          IsSynchronizedWithCurrentItem="True">

This works really well for single selection views. But I'd like to also support multiple selections in the view and have the model bind to the list of selected items.

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

How would I bind the ListView.SelectedItems to a backer property on the ViewModel?

我如何将 ListView.SelectedItems 绑定到 ViewModel 上的支持者属性?

采纳答案by Josh G

Add an IsSelectedproperty to your child ViewModel (OrderViewModelin your case):

IsSelected为您的孩子 ViewModel添加一个属性(OrderViewModel在您的情况下):

public bool IsSelected { get; set; }

Bind the selected property on the container to this (for ListBox in this case):

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

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

IsSelectedis updated to match the corresponding field on the container.

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

You can get the selected children in the view model by doing the following:

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

public IEnumerable<OrderViewModel> SelectedOrders
{
    get { return Orders.Where(o => o.IsSelected); }
}

回答by Simon_Weaver

If you're using MVVM-LIGHT you can use this pattern:

如果您使用的是 MVVM-LIGHT,则可以使用以下模式:

https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner

https://galasoft.ch/posts/2010/05/handling-datagrid-selecteditems-in-an-mvvm-friendly-manner

Not especially elegant but looks like it should be reliable at least

不是特别优雅,但看起来至少应该是可靠的

回答by MichaelLo

One can try creating an attached property.

可以尝试创建附加属性。

Doing so will save one from adding the IsSelectedproperty for each and every list you bind. I have done it for ListBox, but it can be modified for use a in a list view.

这样做可以避免IsSelected为您绑定的每个列表添加属性。我已经为 完成了它ListBox,但可以修改它以在列表视图中使用 a。

<ListBox SelectionMode="Multiple"
         local:ListBoxMultipleSelection.SelectedItems="{Binding SelectedItems}" >


More info: WPF – Binding ListBox SelectedItems – Attached Property VS Style .

更多信息:WPF – 绑定 ListBox SelectedItems – 附加属性 VS 样式

回答by Julio Nobre

I can assure you: SelectedItemsis indeed bindable as a XAML CommandParameter

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

There is a simple solution to this common issue; to make it work you must follow ALLthe following rules:

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

  1. Following Ed Ball's suggestion, on your XAML command databinding, define the CommandParameterattribute BEFOREthe Commandattribute. This a very time-consuming bug.

    enter image description here

  2. Make sure your ICommand's CanExecuteand Executemethods have a parameter of type object. This way you can prevent silencedcast exceptions that occur whenever the databinding's CommandParametertype does not match your Commandmethod's parameter type:

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)  
    {
         // Your code goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)  
    {
        // Your code goes here
    }
    
  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
    }
    

For example, you can either send a ListView/ListBox's SelectedItemsproperty to your ICommandmethods or the ListView/ListBoxitself. Great, isn't it?

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

I hope this prevents someone from spending the huge amount of time I did to figure out how to receive SelectedItemsas a CanExecuteparameter.

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