C# 使用MVVM如何将选定的listview项添加到另一个列表中

C# 使用MVVM如何将选定的listview项添加到另一个列表中,c#,wpf,listview,gridview,C#,Wpf,Listview,Gridview,我正在使用MVVM。我有两个列表视图。第一个listview很好,我可以填充它,它是一个IEnuerable。我想要实现的是,当单击第一个listview中的项目(行)时,我希望将所选项目添加到第二个listview中。有谁能对此提出建议吗 在面板/convas/grid上添加两个ListView并添加此代码。确保为listView1(事件处理程序listView1\u SelectionChanged)注册SelectionChanged事件 使用SelectionChanged事件。然后你可

我正在使用MVVM。我有两个列表视图。第一个listview很好,我可以填充它,它是一个IEnuerable。我想要实现的是,当单击第一个listview中的项目(行)时,我希望将所选项目添加到第二个listview中。有谁能对此提出建议吗

在面板/convas/grid上添加两个ListView并添加此代码。确保为listView1(事件处理程序listView1\u SelectionChanged)注册SelectionChanged事件


使用SelectionChanged事件。然后你可以做类似的事情

Listview2.Items.Add(Listview1.SelectedItem);

为了演示如何使用MVVM实现您想要的功能,我假设您有一个
ItemViewModel
来表示列表视图中的项目。您需要设置
ListView.ItemTemplate
以正确呈现每个项目(或者重写
ToString
方法以返回项目的字符串表示形式)

您需要一个具有三个属性的
MainViewModel

  • Items1
    包含项目列表。在此示例中,列表未更新,因此
    IEnumerable
    就足够了

  • SelectedItem1
    ,它将引用第一个列表视图中当前选定的项目(如果有)

  • Items2
    包含到目前为止所选项目的列表。因为此列表将被更新,所以使用了
    ObservableCollection

  • MainViewModel
    中唯一有趣的代码是
    SelectedItem1
    的setter。只要第一个列表视图中的选择发生更改,就会修改此选项。发生这种情况时,所选项目将添加到
    Items2
    集合中

    public class MainViewModel {
    
      ItemViewModel selectedItem1;
    
      public MainViewModel(IEnumerable<ItemViewModel> items1) {
        Items1 = items1;
        Items2 = new ObservableCollection<ItemViewModel>();
      }
    
      public IEnumerable<ItemViewModel> Items1 { get; private set; }
    
      public ObservableCollection<ItemViewModel> Items2 { get; private set; }
    
      public ItemViewModel SelectedItem1 {
        get { return this.selectedItem1; }
        set {
          this.selectedItem1 = value;
          if (this.selectedItem1 != null && !Items2.Contains(this.selectedItem1))
            Items2.Add(this.selectedItem1);
        }
      }
    
    }
    
    第一个
    ListView
    绑定到视图模型中的
    Items1
    。当更改
    列表视图中的选择时,数据绑定将确保在视图模型中设置
    SelectedItem1
    。然后,setter中的代码将更新
    Items2
    属性,因为这是一个
    可观察的集合
    ,新添加的项目将使用数据绑定推送到第二个
    列表视图

    在您的情况下,可以通过绑定
    SelectedItem
    属性来处理
    ListView
    中的选择事件。然而,有时不可能使用数据绑定来“处理事件”。解决方案可能是在视图的代码隐藏中添加事件处理程序,但这通常会导致视图模型和视图之间产生不必要的依赖关系。相反,您可以使用。通过编写自己的
    Behavior
    类,您可以处理事件并将其转换为数据绑定到的内容,从而打破不必要的依赖关系。但是,要解决您的特定问题,它不是必需的

    请注意,如果要使用
    行为
    ,则不再需要Blend SDK。您可以使用NuGet向
    Blend.Interactivity.Wpf
    (或类似的包,具体取决于您的框架)添加依赖项,以获取使用Blend行为所需的单个DLL


    因此,要扩展如何在单击第二个列表中的项目时取消选择它们,您需要使用行为。尝试使用与上述相同的技巧,即在绑定到第二个
    列表视图
    SelectedItem
    的属性的setter中执行操作将失败,因为向第二个
    列表视图
    添加新项可能会立即选择该项,然后该项将立即删除新添加的项-这不是您想要的需要

    这是一个
    MouseLeftButtonUpBehavior
    ,如果没有代码隐藏,当在控件上释放鼠标左键时,将允许您执行命令:

    class MouseLeftButtonUpBehavior : Behavior<Control> {
    
      public static readonly DependencyProperty CommandProperty
        = DependencyProperty.Register(
          "Command",
          typeof(ICommand),
          typeof(MouseLeftButtonUpBehavior)
        );
    
      public ICommand Command
      {
        get { return (ICommand) GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
      }
    
      protected override void OnAttached() {
        AssociatedObject.MouseLeftButtonUp += OnMouseLeftButtonUp;
      }
    
      protected override void OnDetaching() {
        AssociatedObject.MouseLeftButtonUp -= OnMouseLeftButtonUp;
      }
    
      void OnMouseLeftButtonUp(Object sender, MouseButtonEventArgs mouseButtonEventArgs) {
        if (Command != null)
          Command.Execute(mouseButtonEventArgs);
      }
    
    }
    
    视图模型中需要两个新属性:

    public ItemViewModel SelectedItem2 { get; set; }
    
    public ICommand DeselectCommand { get; private set; }
    
    SelectedItem2
    用于跟踪在第二个列表视图中选择的项目。当在第二个列表视图中触发鼠标左键向上事件时,将执行
    取消选择命令
    。要真正做一些有用的事情,您需要创建一个命令。您可以使用
    DelegateCommand
    。这个类不是WPF的一部分,但是如果你用谷歌搜索它,你可以很容易地找到一个合适的实现。
    DelegateCommand
    只是一种创建WPF
    ICommand
    的方法,它执行您选择的委托

    MainViewModel
    的构造函数中:

    <StackPanel>
      <ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
      <ListView ItemsSource="{Binding Items2}"/>
    </StackPanel>
    
    DeselectCommand = new DelegateCommand(_ => Deselect());
    
    void Deselect() {
      if (SelectedItem2 != null)
        Items2.Remove(SelectedItem2);
    }
    
    然后您需要在
    MainViewModel
    中实现
    取消选择

    <StackPanel>
      <ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
      <ListView ItemsSource="{Binding Items2}"/>
    </StackPanel>
    
    DeselectCommand = new DelegateCommand(_ => Deselect());
    
    void Deselect() {
      if (SelectedItem2 != null)
        Items2.Remove(SelectedItem2);
    }
    

    将所有这些放在一起将在单击第二个列表视图时从第二个列表视图中删除项目,并且视图中没有任何代码,否则可能会在视图到视图模型之间创建不必要的依赖关系(例如,视图中的代码必须知道它应该调用视图模型上的
    取消选择
    ).

    下面的答案都不符合你的需要?@Mikedklerk——你知道eran otzap建议的第三步吗?我用的是MVVM。马丁的答案当然是最好的。我不熟悉abbrevation MVVM,但我对MVC并不熟悉。我应该把你的问题读得更清楚。我的答案太老套了,不能用在类似MVC-a的解决方案中。@Mikedklerk——没问题,也谢谢你的意见。它确实为我指明了正确的方向,我又学到了一些我不知道的东西。这很有效。同样的概念会适用于从第二个网格中取消选择吗?@Calvin:请更详细地描述您所说的“从第二个网格中取消选择”是什么意思。对不起,我是说listview。我在您的示例中所做的就是给出两个listview名称。从您的示例中,在第一个listview中选择的任何内容都将添加到observablecollection,后者通过第二个listview的itemsource填充第二个listview。假设我想从第二个listview中取消选择一个项目。这应该如何通过MVVM处理?我所做的是为第二个listview“MouseLeftButtonUp”事件使用代码隐藏。我实例化viewmodel,然后访问“SelectedItems”属性并使用