我正在使用MVVM。我有两个listview。第一个listview很好,我可以填充它,它是一个IEnuerable。我想要实现的是当点击第一个列表视图中的项目(行)时,我想将所选项添加到第二个列表视图中。任何人都可以就此提出建议。
答案 0 :(得分:3)
为了演示如何使用MVVM执行您想要的操作,我假设您有ItemViewModel
表示列表视图中的项目。您需要设置ListView.ItemTemplate
以正确呈现每个项目(或覆盖ToString
方法以返回项目的字符串表示形式。)
您需要一个包含三个属性的MainViewModel
:
Items1
包含项目列表。在此示例中,列表未更新,因此IEnumerable<ItemViewModel>
就足够了。
SelectedItem1
将引用第一个列表视图中的当前所选项目(如果有)。
Items2
包含您目前为止所选项目的列表。由于此列表将更新,因此使用了ObservableCollection<ItemViewModel>
。
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);