WPF中的EventTrigger
我想从通过InvokeCommandAction选中复选框的列表框中获取SelectedItems,并将其存储在obsevableCollection SelectedItems中,但我无法使SelectedItemChangedCommand正常工作(断点未命中),也不确定如何填充SelectedItems集合中的项。我尝试了以下操作,希望一旦选中或取消选中复选框,SelectedItemChangedCommand就会被调用,并且我可以在这里调用一个方法来填充SelectedItems 请注意,我正在寻找一种方法来实现这一点没有任何代码落后WPF中的EventTrigger,wpf,data-binding,Wpf,Data Binding,我想从通过InvokeCommandAction选中复选框的列表框中获取SelectedItems,并将其存储在obsevableCollection SelectedItems中,但我无法使SelectedItemChangedCommand正常工作(断点未命中),也不确定如何填充SelectedItems集合中的项。我尝试了以下操作,希望一旦选中或取消选中复选框,SelectedItemChangedCommand就会被调用,并且我可以在这里调用一个方法来填充SelectedItems 请注
<ListBox Margin="45,7,0,0" VerticalAlignment="Top" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
ItemsSource="{Binding ListItems}"
SelectionMode="Multiple" Height="146">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<CheckBox Margin="5,2"
IsChecked="{TemplateBinding IsSelected}">
<ContentPresenter />
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}" CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
更新的Xaml文件
<Window x:Class="stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:stack"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<ListBox x:Name="myListBox" Margin="45,7,0,0" VerticalAlignment="Top"
ItemsSource="{Binding ListItems}"
SelectionMode="Multiple" Height="146">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<CheckBox
Margin="5,2"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
>
<ContentPresenter />
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"
CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
</Grid>
</Window>
我将listbox绑定到视图模型中定义的observableCollection ListItems,如下所示
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace stack
{
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<string> ListItems { get; set; }
public ObservableCollection<string> SelectedListItems { get; set; }
public RelayCommand SelectedItemChangedCommand { get; set; }
public string _selectedItem;
public string SelectedItem
{
get => _selectedItem;
set
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
public bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
public MainViewModel()
{
ListItems = new ObservableCollection<string>();
ListItems.Add("One");
ListItems.Add("Two");
ListItems.Add("three");
ListItems.Add("Four");
ListItems.Add("Five");
SelectedItemChangedCommand = new RelayCommand(this.ExecuteItemChanged);
}
public void ExecuteItemChanged(object parameter)
{
if (IsSelected)
{
SelectedListItems.Add(SelectedItem);
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler _propertyChangedEventHandler = PropertyChanged;
_propertyChangedEventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用系统组件模型;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows.Input;
名称空间堆栈
{
公共类MainViewModel:INotifyPropertyChanged
{
公共ObservableCollection列表项{get;set;}
公共ObservableCollection SelectedListItems{get;set;}
public relay命令选择editemchangedCommand{get;set;}
公共字符串_selectedItem;
公共字符串SelectedItem
{
get=>\u选择编辑项;
设置
{
_选择editem=值;
OnPropertyChanged(“SelectedItem”);
}
}
公营学校选举产生;
公选学校
{
get=>\u被选中;
设置
{
_isSelected=值;
不动产变更(“IsSelected”);
}
}
公共主视图模型()
{
ListItems=新的ObservableCollection();
列表项。添加(“一”);
添加(“两个”);
增加(“三”);
增加(“四”);
增加(“五”);
选择EditemChangedCommand=new RelayCommand(this.ExecuteItemChanged);
}
public void ExecuteItemChanged(对象参数)
{
如果(当选)
{
SelectedListItems.Add(SelectedItem);
}
}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged(字符串propertyName)
{
PropertyChangedEventHandler\u PropertyChangedEventHandler=PropertyChanged;
_propertyChangedEventHandler?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
模板绑定
很便宜,但它不做双向绑定。因此,项目不会被选中。您需要使用模板parent的相对资源进行常规绑定:
<CheckBox
Margin="5,2"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
>
并确保列表框上有x:Name=“myListBox”
:CommandParameter绑定需要它来查找SelectedItems
最后:ExecuteItemChanged()非常脆弱。您的主视图模型属性已选择
和SelectedItem
未绑定到任何内容。它们永远都是假的和空的。每次选择更改时,您都会执行该命令并将第一个选定项作为参数
传入,然后忽略它并查看false
是否仍然是false
,它就是。否则,viewmodel的SelectedItem属性仍将为空,因为您也从未更新过该属性
您要做的是:当选择更改时,将当前选定项的整个集合传递到您的命令中。用控件中的当前状态替换viewmodel当前选定项的整个集合。您必须,必须,必须绑定SelectedItems作为上面的CommandParameter
去掉viewmodel上的SelectedItem
和IsSelected
,它们没有任何作用
如果可能的话,千万不要涉足维护两个列表并试图使它们零碎地保持同步的业务。总是一团糟。在这种情况下你不需要这么做
public void ExecuteItemChanged(object parameter)
{
// ListBox.SelectedItems is System.Windows.Controls.SelectedItemCollection,
// a precambrian monster that's declared internal in PresentationFramework.dll.
// However, it does implement non-generic IList, so cast it to that.
if (parameter is System.Collections.IList selectedItems)
{
if (SelectedListItems == null)
{
SelectedListItems = new ObservableCollection<String>();
}
SelectedListItems.Clear();
foreach (string item in selectedItems)
{
SelectedListItems.Add(item);
}
}
}
public void ExecuteItemChanged(对象参数)
{
//ListBox.SelectedItems是System.Windows.Controls.SelectedItemCollection,
//在PresentationFramework.dll中声明为内部的前寒武纪怪物。
//但是,它确实实现了非通用的IList,所以将其转换为该类。
if(参数为System.Collections.IList selectedItems)
{
如果(SelectedListItems==null)
{
SelectedListItems=新的ObservableCollection();
}
SelectedListItems.Clear();
foreach(selectedItems中的字符串项)
{
SelectedListItems。添加(项);
}
}
}
谢谢,我根据您的建议更新了Xaml文件,但仍然无法填充所选项目:-(,我已将已完成的ViewModel类粘贴到此处。我想我缺少了其他内容ExecuteItemChanged(对象参数)
已断开。viewmodel的SelectedItem
属性是什么?Null。它未绑定。您要麻烦地将列表框中的第一个选定项作为参数传入
public void ExecuteItemChanged(object parameter)
{
// ListBox.SelectedItems is System.Windows.Controls.SelectedItemCollection,
// a precambrian monster that's declared internal in PresentationFramework.dll.
// However, it does implement non-generic IList, so cast it to that.
if (parameter is System.Collections.IList selectedItems)
{
if (SelectedListItems == null)
{
SelectedListItems = new ObservableCollection<String>();
}
SelectedListItems.Clear();
foreach (string item in selectedItems)
{
SelectedListItems.Add(item);
}
}
}