【问题标题】:How to bind multiple selection of listview to viewmodel?如何将列表视图的多项选择绑定到视图模型?
【发布时间】:2011-08-10 02:45:29
【问题描述】:

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

SelectedItem={Binding path= selectedItems}

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

【问题讨论】:

标签: wpf mvvm selection


【解决方案1】:

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

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

要使其发挥作用,您必须遵循以下所有规则

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

  2. 确保您的 ICommandCanExecuteExecute 方法具有 object 类型的参数。这样,您可以防止在数据绑定 CommandParameter 类型与命令方法的参数类型不匹配时发生的 silenced 强制转换异常。

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
    {
        // Your goes here
    }
    
    private bool OnDeleteSelectedItemsExecute(object SelectedItems)
    {
        // Your goes here
    }
    

例如,您可以将 listview/listbox 的 SelectedItems 属性发送给您的 ICommand 方法或它自己的 listview/listbox。很好,不是吗?

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

【讨论】:

  • IMO 这篇文章应该被标记为最佳答案 - 简单并利用 API。属性顺序并不明显,这是一个很好的发现。
  • 这种方法确实适合 OP 问题,但要拥有真正的数据绑定,请在此线程中查看我的答案。它不需要按钮单击或任何事件并作为命令参数传递,它就像任何其他支持数据绑定的控件一样工作。我认为这是一种更好的方法。
【解决方案2】:

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

由于允许从 View 访问 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);
}

编辑

这是一个极简示例,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);
    }

【讨论】:

  • 如何将 ListViewItem 解析为特定对象?因为我对 listviewItem 无能为力?
  • 如果你的 ListViewItem 是 MyType 类型,你可以使用它: List mySelectedItems = new List(); foreach(MyType mytype in myListView.SelectedItems) ...
  • @Ruben - 我添加了一个简单的例子。祝你好运:)
  • 非常感谢,但我也想更改字体,我这样做:foreach (ListViewItem x in DropListView.SelectedItems) { x.FontStyle = FontStyles.Oblique; }
  • 但是他给出了错误,因为 SelectedItems 现在不是 ListViewItem 的对象?
【解决方案3】:

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

<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>

然后在视图模型中:

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

【讨论】:

    【解决方案4】:

    如果您已经在使用 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 都会选取所选项目。

    【讨论】:

    【解决方案5】:

    你不能绑定,但你可以作为 CommandParameter 发送给 Command。

    【讨论】:

      【解决方案6】:

      作为 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)。

      【讨论】:

      • 这不是一个好习惯,因为除非没有其他解决方案,否则 MVVM 确实不会提升代码背后的代码。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

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

        希望对你有帮助

        【讨论】:

        • 问题是那些帖子后面没有完整的代码(下载不起作用),所以目前有点用处......
        • @etwas77 第三个仍然有效(这是您真正需要的唯一一个)
        • @ghord:它不进行双向绑定。例如如果您设置 SelectedItems 它不会更新 ListView
        【解决方案9】:

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

        从这篇文章How to Databind to a SelectedItems property in WPF 找到了很多帮助

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-05
          • 1970-01-01
          • 2020-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多