使用MVVM如何将选定的listview项添加到另一个

时间:2012-10-15 18:12:29

标签: c# wpf listview gridview

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

3 个答案:

答案 0 :(得分:3)

为了演示如何使用MVVM执行您想要的操作,我假设您有ItemViewModel表示列表视图中的项目。您需要设置ListView.ItemTemplate以正确呈现每个项目(或覆盖ToString方法以返回项目的字符串表示形式。)

您需要一个包含三个属性的MainViewModel

  1. Items1包含项目列表。在此示例中,列表未更新,因此IEnumerable<ItemViewModel>就足够了。

  2. SelectedItem1将引用第一个列表视图中的当前所选项目(如果有)。

  3. Items2包含您目前为止所选项目的列表。由于此列表将更新,因此使用了ObservableCollection<ItemViewModel>

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

    请注意,此简单视图模型未实现INotifyPropertyChanged,因为此示例不需要它。

    视图与这样的XAML绑定到视图模型(例如,包含此XAML的任何内容的DataContext应设置为MainViewModel的实例):

    <StackPanel>
      <ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
      <ListView ItemsSource="{Binding Items2}"/>
    </StackPanel>
    

    第一个ListView绑定到视图模型中的Items1。当ListView中的选择被更改时,数据绑定将确保在视图模型中设置SelectedItem1。然后,setter中的代码将更新Items2属性,因为这是ObservableCollection<T>个新项目,将使用数据绑定推送 - 在本例中为第二个ListView

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

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


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

    这是一个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);
      }
    
    }
    

    必须将XAML修改为此(您可以使用NuGet添加对Blend.Interactivity.Wpf包的引用,以便能够向控件添加交互):

    <StackPanel>
      <ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
      <ListView ItemsSource="{Binding Items2}" SelectedItem="{Binding SelectedItem2}">
        <i:Interaction.Behaviors>
          <local:MouseLeftButtonUpBehavior Command="{Binding DeselectCommand}"/>
        </i:Interaction.Behaviors>
      </ListView>
    </StackPanel>
    

    视图模型中需要两个新属性:

    public ItemViewModel SelectedItem2 { get; set; }
    
    public ICommand DeselectCommand { get; private set; }
    

    SelectedItem2用于跟踪在第二个列表视图中选择的项目。在第二个列表视图中触发鼠标左键按钮事件时执行DeselectCommand。要实际执行一些有用的操作,您需要创建一个命令。您可以使用DelegateCommand。这个类不是WPF的一部分,但如果你谷歌它,你可以很容易地找到一个合适的实现。 DelegateCommand只是一种创建WPF ICommand的方法,可以执行您选择的委托。

    MainViewModel的构造函数中:

    DeselectCommand = new DelegateCommand(_ => Deselect());
    

    然后您需要在Deselect中实施MainViewModel

    void Deselect() {
      if (SelectedItem2 != null)
        Items2.Remove(SelectedItem2);
    }
    

    将所有这些组合在一起将在单击时从第二个列表视图中删除项目,并且在视图中没有任何代码隐藏,否则可能会从您查看到视图模型(例如视图中的代码)中创建不需要的依赖项必须知道它应该在视图模型上调用Deselect

答案 1 :(得分:0)

在面板/画布/网格上添加两个列表视图并添加此代码。确保为listView1注册SelectionChanged事件(事件处理程序listView1 SelectionChanged)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void listView1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            listView2.Items.Add((listView1.SelectedItem));
        }

        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            listView1.Items.Add("test 1");
            listView1.Items.Add("test 2");
        }
    }
}

答案 2 :(得分:0)

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

的事情
Listview2.Items.Add(Listview1.SelectedItem);