我希望从列表框中获取SelectedItems,其中通过InvokeCommandAction选择复选框,并将其存储在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>我将列表框绑定到视图模型中定义为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));
}
}
}发布于 2019-08-23 16:07:23
TemplateBinding很便宜,但它不进行双向绑定。因此,项目没有被选中。您需要与RelativeSource of TemplatedParent定期绑定。
<CheckBox
Margin="5,2"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}"
>请注意,您正在将CheckBox.IsChecked绑定到ListBoxItem.IsSelected。模板的父版本是一个ListBoxItem,而不是您的主要视图模型。
其次,您希望将SelectedItems、复数属性传递给您的命令。SelectedItem是单数的。只有一个项目。这将是最上面选择的项目时,许多被选中。您的列表框中有SelectionMode="Multiple“,所以我假设您想要完整的选择。
<i:InvokeCommandAction
Command="{Binding SelectedItemChangedCommand}"
CommandParameter="{Binding ElementName=myListBox, Path=SelectedItems}"
/>并确保x:Name="myListBox"在ListBox上: CommandParameter绑定需要这样才能找到SelectedItems。
最后: ExecuteItemChanged()非常坏。您的主要视图模型属性IsSelected和SelectedItem没有绑定到任何东西。它们一直都是假的和空的。每次选择更改时,都执行命令并将第一个选定项作为parameter传递,然后忽略它,然后查看false是否仍然是false,它是false。如果不是,则视图模型的SelectedItem属性仍然为空,因为您也从未更新过该属性。
下面是您想要做的事情:当选择更改时,将当前选定项的整个集合传递到您的命令中。用控件中的当前状态替换视图模型当前选定项的整个集合。您必须、必须将SelectedItems绑定为上面的CommandParameter。
去掉视图模型上的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);
}
}
}https://stackoverflow.com/questions/57629381
复制相似问题