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

发布于 2024-11-02 19:11:55 字数 260 浏览 2 评论 0原文

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

SelectedItem={Binding path= selectedItems}

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

I am implementing a listview, and a button next to it. I have to be able that when i select multiple items in a listview, and then click on a button, then the selected items are put into a list. But my question is , how do i bind the selected items towards the viewmodel?
I changed my selectionmode to multiple. But then, do i just have to do:

SelectedItem={Binding path= selectedItems}

and then make in my viewmodel a property selectedItems, and it will set these items i have selected? Or what is the right solution to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

酒与心事 2024-11-09 19:11:55

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

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

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

  1. 遵循Ed Ball 的建议 ',在 XAML 命令数据绑定中,在 Command 属性之前定义 CommandParameter 属性。这是一个非常耗时的错误。

    在此处输入图像描述

  2. 确保您的 ICommandCanExecute和执行方法有一个对象类型的参数。这样,您可以防止每当数据绑定 CommandParameter 类型与命令方法的参数类型不匹配时发生静默强制转换异常。

    private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)
    {
        // 你的位置在这里
    }
    
    私有 bool OnDeleteSelectedItemsExecute(object SelectedItems)
    {
        // 你的位置在这里
    }
    

例如,您可以将列表视图/列表框的 SelectedItems 属性发送到您的 ICommand 方法或列表视图/列表框本身。太棒了,不是吗?

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

Like Doctor has already pointed out, you can bind SelectedItems to XAML CommandParameter

After a lot of digging and googling, I have finally found a simple solution to this common issue.

To make it work you must follow ALL the following rules:

  1. Following Ed Ball's suggestion', on you XAML command databinding, define CommandParameter property BEFORE Command property. This a very time-consuming bug.

    enter image description here

  2. Make sure your ICommand's CanExecute and Execute methods have a parameter of object type. This way you can prevent silenced cast exceptions that occurs whenever databinding CommandParameter type does not match your command method's parameter type.

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

For example, you can either send a listview/listbox's SelectedItems property to you ICommand methods or the listview/listbox it self. Great, isn't it?

Hope it prevents someone spending the huge amount of time I did to figure out how to receive SelectedItems as CanExecute parameter.

趴在窗边数星星i 2024-11-09 19:11:55

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

希望这有帮助

It's kind of tricky to do this Mutliple Selection in MVVM, because the SelectedItems property isn't a Dependency Property. However, there are some tricks you can use. I found this triology of blog posts that describe the matter in some details and provide some useful solutions.

Hope this helps

爱她像谁 2024-11-09 19:11:55

如果您已经使用 System.Windows.Interactivity 和 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 上的选择发生更改,您的 ViewModel 就会拾取所选项目。

If you are using System.Windows.Interactivity and Microsoft.Expression.Interactions already, here is a workaround without any other code/behaviour to mess around. If you need these, it can be download from here

This workaround make use of interactivity event trigger and interactions set property mechanism in above assemblies.

Additional namespace declaration in 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>

View Model:

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

In example above, your ViewModel will pick up the selected items whenever the selection on ListView changed.

花桑 2024-11-09 19:11:55

您可以做的是在代码隐藏中处理 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);
    }

What you can do is you can handle the Button_Click(...) in your code-behind. Then in that code-behind method you can create a List of selected items by iterating over the selected items of the listView.

Since it is allowed to access the ViewModel from the View you can now call a method on your ViewModel and pass the list of selected items as a parameter.

I'm not sure if this would also work with Bindings only, however it is not bad practice to use code-behind as well.

Example Code:

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

EDIT

Here is a minimalist example, XAML:

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

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

CODE-BEHIND:

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);
    }
遥远的绿洲 2024-11-09 19:11:55

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

我从这篇文章中找到了很多帮助 How to Databind to WPF 中的 SelectedItems 属性

Unfortunately the SelectedItems is a read only not bindable property.

I found a lot of help from this article How to Databind to a SelectedItems property in WPF

下壹個目標 2024-11-09 19:11:55

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

If you are using Metro/WinRT you may want to look at the WinRTXXAMLToolkit as it offers a bindable SelectedItems dependency property as one of its extensions.

So尛奶瓶 2024-11-09 19:11:55

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

You can't bind, but you can send to Command as an CommandParameter.

携余温的黄昏 2024-11-09 19:11:55

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

As a slight variation on Christian's post, I implemented similar code using the ListView.SelectionChanged event. Instead of calling a method on the ViewModel, I set a property called 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;
}

This way, ViewModel.SelectedItems is available for any command you might have in your ViewModel and it can be used for data binding (if you turn it into an ObservableCollection).

你在看孤独的风景 2024-11-09 19:11:55

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

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

I did a solution for this, to me this was simple enough.

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

Then in the viewmodel:

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

SelectedModels is the list where I wanted the selection to be filled.

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

         SelectedModels = tempModelInfo;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文