Wpf 如何将listview的多个选择绑定到viewmodel?

Wpf 如何将listview的多个选择绑定到viewmodel?,wpf,mvvm,selection,Wpf,Mvvm,Selection,我正在实现一个listview,以及它旁边的一个按钮。我必须能够在listview中选择多个项目,然后单击按钮,然后将所选项目放入列表中。但我的问题是,如何将所选项目绑定到viewmodel? 我将selectionmode更改为multiple。但是,我是否必须这样做: SelectedItem={Binding path= selectedItems} 然后在我的viewmodel中创建一个属性selectedItems,它将设置我选择的这些项?或者什么是正确的解决方案呢?不幸的是,Sel

我正在实现一个listview,以及它旁边的一个按钮。我必须能够在listview中选择多个项目,然后单击按钮,然后将所选项目放入列表中。但我的问题是,如何将所选项目绑定到viewmodel? 我将selectionmode更改为multiple。但是,我是否必须这样做:

SelectedItem={Binding path= selectedItems}

然后在我的viewmodel中创建一个属性selectedItems,它将设置我选择的这些项?或者什么是正确的解决方案呢?

不幸的是,SelectedItems是一个只读的不可绑定属性


我从这篇文章中找到了很多帮助

您可以做的是处理代码中的按钮点击(…)。然后,在该代码隐藏方法中,您可以通过迭代listView的选定项来创建选定项的列表

由于允许从视图访问ViewModel,您现在可以调用ViewModel上的方法,并将所选项目列表作为参数传递

我不确定这是否也只适用于绑定,但是使用代码隐藏也是一种不错的做法

示例代码:

public void Button_Click(object sender, EventArguments arg)
{
  List<ListViewItem> mySelectedItems = new List<ListViewItem>();

  foreach(ListViewItem item in myListView.SelectedItems)
  {
    mySelectedItems.Add(item);
  }

  ViewModel.SomeMethod(mySelectedItems);
}
public void按钮\u单击(对象发送者,事件参数参数)
{
List mySelectedItems=新列表();
foreach(myListView中的ListViewItem项。选择编辑项)
{
mySelectedItems.Add(项目);
}
ViewModel.SomeMethod(mySelectedItems);
}
编辑

下面是一个极简主义的示例,XAML:

<DataTemplate
            x:Key="CarTemplate"
            DataType="{x:Type Car}">
</DataTemplate>

<ListView x:Name="myListView"
          ItemsSource="{Binding Path=Cars}"
          ItemTemplate="{StaticResource CarTemplate}">
</ListView>

代码隐藏:

public void Button_Click(object sender, EventArguments arg)
    {
      List<Car> mySelectedItems = new List<Car>();

      foreach(Car item in myListView.SelectedItems)
      {
        mySelectedItems.Add(item);
      }

      ViewModel.SomeMethod(mySelectedItems);
    }
public void按钮\u单击(对象发送者,事件参数参数)
{
List mySelectedItems=新列表();
foreach(myListView中的汽车项目。选择EditEMS)
{
mySelectedItems.Add(项目);
}
ViewModel.SomeMethod(mySelectedItems);
}

在MVVM中进行这种多重选择有点棘手,因为
SelectedItems
属性不是
依赖属性。但是,您可以使用一些技巧。我发现这三篇博客文章详细描述了这件事,并提供了一些有用的解决方案


希望这对您有所帮助

如果您使用的是
Metro/WinRT
,您可能需要查看,因为它提供了一个可绑定的
SelectedItems
依赖属性作为其扩展之一。

作为Christian帖子的一个细微变化,我使用ListView.SelectionChanged事件实现了类似的代码。我没有在ViewModel上调用方法,而是设置了一个名为SelectedItems的属性:

public void ListView_SelectionChanged( object s, SelectionChangedEventArgs e ) {
    List<Car> mySelectedItems = new List<Car>();

    foreach( Car item in myListView.SelectedItems )
        mySelectedItems.Add(item);

    ViewModel.SelectedItems = mySelectedItems;
}
public void ListView\u SelectionChanged(对象s,SelectionChangedEventArgs e){
List mySelectedItems=新列表();
foreach(myListView.SelectedItems中的汽车项目)
mySelectedItems.Add(项目);
ViewModel.SelectedItems=mySelectedItems;
}

这样,ViewModel.SelectedItems可用于ViewModel中的任何命令,并可用于数据绑定(如果将其转换为可观察集合)。

无法绑定,但您可以将命令作为CommandParameter发送。

如果您已经在使用System.Windows.Interactive和Microsoft.Expression.Interactions,这里有一个解决方法,不需要任何其他代码/行为。如果您需要这些,可以从

此解决方案在上述程序集中使用交互性事件触发器和交互集属性机制

XAML中的附加名称空间声明

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
XAML:

<ListView Name="MyListView" ItemsSource="{Binding ModelList}" DisplayMemberPath="Name"  Grid.Column="0">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
      <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedItems" Value="{Binding Path=SelectedItems, ElementName=MyListView}"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</ListView>
public class ModelListViewModel
{
  public ObservableCollection<Model> ModelList { get; set; }
  public ObservableCollection<Model> SelectedModels { get; set; }

  public ModelListViewModel() {
    ModelList = new ObservableCollection<Model>();
    SelectedModels = new ObservableCollection<Model>();
  }

  public System.Collections.IList SelectedItems {
    get {
      return SelectedModels;
    }
    set {
      SelectedModels.Clear();
      foreach (Model model in value) {
        SelectedModels.Add(model);
      }
    }
  }
}

查看模型:

<ListView Name="MyListView" ItemsSource="{Binding ModelList}" DisplayMemberPath="Name"  Grid.Column="0">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
      <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}" PropertyName="SelectedItems" Value="{Binding Path=SelectedItems, ElementName=MyListView}"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</ListView>
public class ModelListViewModel
{
  public ObservableCollection<Model> ModelList { get; set; }
  public ObservableCollection<Model> SelectedModels { get; set; }

  public ModelListViewModel() {
    ModelList = new ObservableCollection<Model>();
    SelectedModels = new ObservableCollection<Model>();
  }

  public System.Collections.IList SelectedItems {
    get {
      return SelectedModels;
    }
    set {
      SelectedModels.Clear();
      foreach (Model model in value) {
        SelectedModels.Add(model);
      }
    }
  }
}
公共类模型ListViewModel
{
公共ObservableCollection模型列表{get;set;}
公共ObservableCollection SelectedModels{get;set;}
公共模型ListViewModel(){
ModelList=新的ObservableCollection();
SelectedModels=新的ObservableCollection();
}
public System.Collections.IList SelectedItems{
得到{
返回所选模型;
}
设置{
SelectedModels.Clear();
foreach(价值模型){
选择模型。添加(模型);
}
}
}
}
在上面的示例中,每当ListView上的选择发生更改时,ViewModel将拾取所选项目。

如前所述,您可以将SelectedItems绑定到XAMLCommandParameter

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

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

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

  • 确保您的ICommandCanExecuteExecute方法具有object类型的参数。通过这种方式,可以防止在数据绑定CommandParameter类型与命令方法的参数类型不匹配时发生沉默强制转换异常

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
    {
        // Your goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)
    {
        // Your goes here
    }
    
  • 例如,您可以将listview/listbox的SelectedItems属性发送给您的ICommand方法或listview/listbox本身。太好了,不是吗


    希望它能防止有人花费大量的时间来找出如何将SelectedItems作为CanExecute参数来接收。

    我为此做了一个解决方案,对我来说这很简单

    <ListBox ItemsSource="{Binding ListOfModel}" x:Name="ModelList"
                                    SelectedItem="{Binding SelectedModel, Mode=TwoWay}">
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="SelectionChanged">
                                        <i:InvokeCommandAction Command="{Binding ExecuteListBoxSelectionChange}" CommandParameter="{Binding ElementName=ModelList}">
                                        </i:InvokeCommandAction>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </ListBox>
    
    
    
    然后在viewmodel中:

    public ICommand ExecuteListBoxSelectionChange { get; private set; }
    ExecuteListBoxSelectionChange = DelegatingCommand<ListBox>.For(ListBoxSelectionChnageEvent).AlwaysEnabled();
    
    public ICommand ExecuteListBoxSelectionChange{get;private set;}
    ExecuteListBoxSelectionChange=DelegatingCommand.For(ListBoxSelectionChanageEvent).AlwaysEnabled();
    
    精选