如何将多个listview选项绑定到viewmodel?

时间:2011-04-21 07:53:39

标签: wpf mvvm selection

我正在实现一个列表视图,旁边有一个按钮。我必须能够在列表视图中选择多个项目,然后单击按钮,然后将所选项目放入列表中。但我的问题是,如何将所选项目绑定到视图模型? 我将selectionmode改为多个。但是,我必须这样做:

SelectedItem={Binding path= selectedItems}

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

9 个答案:

答案 0 :(得分:36)

就像Doctor已经指出的那样,您可以将 SelectedItems 绑定到XAML CommandParameter

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

要使其有效,您必须遵循以下所有规则

  1. 关注Ed Ball's suggestion',在您的XAML命令数据绑定中,在命令属性之前定义 CommandParameter 属性。这是一个非常耗时的错误。

    enter image description here

  2. 确保 ICommand CanExecute 执行方法的参数为对象类型。这样,只要数据绑定 CommandParameter 类型与命令方法的参数类型不匹配,就可以防止出现沉默强制转换异常。

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
    {
        // Your goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)
    {
        // Your goes here
    }
    
  3. 例如,您可以将listview / listbox的 SelectedItems 属性发送给 ICommand 方法或自己的listview / listbox。好的,不是吗?

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

答案 1 :(得分:22)

在MVVM中执行此多重选择有点棘手,因为SelectedItems属性不是Dependency Property。但是,您可以使用一些技巧。我发现这篇博客文章的三部曲在一些细节中描述了这个问题并提供了一些有用的解决方案。

希望这有帮助

答案 2 :(得分:13)

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

下载

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

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上的选择发生更改时,ViewModel都会选择所选项目。

答案 3 :(得分:12)

你可以做的是你可以在代码隐藏中处理Button_Click(...)。然后在该代码隐藏方法中,您可以通过迭代listView的所选项来创建所选项的列表。

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

我不确定这是否也适用于Bindings,但是使用代码隐藏也不错。

示例代码:

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);
}

修改

这是一个极简主义的例子,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);
    }

答案 4 :(得分:6)

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

我在本文How to Databind to a SelectedItems property in WPF

中找到了很多帮助

答案 5 :(得分:4)

您无法绑定,但可以作为CommandParameter发送给Command。

答案 6 :(得分:3)

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

答案 7 :(得分:0)

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

<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();

SelectedModels是我希望填充选区的列表。

    private void ListBoxSelectionChnageEvent(ListBox modelListBox)
    {
        List<ModelInfo> tempModelInfo = new List<ModelInfo>();
         foreach(ModelInfo a in modelListBox.SelectedItems)
             tempModelInfo.Add(a);

         SelectedModels = tempModelInfo;
    }

答案 8 :(得分:-1)

作为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;
}

这样,ViewModel.SelectedItems可用于ViewModel中可能包含的任何命令,它可用于数据绑定(如果将其转换为ObservableCollection)。