我有一个列表视图,它将 SelectionChanged 上的所选项目正确发送到我的视图模块。当选择一个或多个项目时,SelectionChanged 属性会发送选定的项目,但是当取消选择一个或多个项目时,它不会触发 SelectionChanged 属性。
这就是我所做的。
XAML
<ListView
x:Name="myListView"
SelectionMode="Extended">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding GetSelectedItemsCommand}" CommandParameter="{Binding ElementName=myListView, Path=SelectedItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn Header="Nombre" DisplayMemberBinding="{Binding FileName}" />
<GridViewColumn Header="Dirección" DisplayMemberBinding="{Binding FilePath}" />
</GridView>
</ListView.View>
</ListView>
视图模型
private ObservableCollection<FileItem> _selectedItems = new ObservableCollection<FileItem>();
public ObservableCollection<FileItem> SelectedItems
{
get { return _selectedItems; }
set { SetProperty(ref _selectedItems, value); }
}
private DelegateCommand<ObservableCollection<Object>> _getSelectedItems;
public DelegateCommand<ObservableCollection<Object>> GetSelectedItemsCommand =>
_getSelectedItems ?? (_getSelectedItems = new DelegateCommand<ObservableCollection<Object>>(ExecuteGetSelectedItems));
private void ExecuteGetSelectedItems(ObservableCollection<Object> fileItems)
{
foreach (var file in fileItems)
{
FileItem fileItem = (FileItem)file;
if (fileItem != null && !SelectedItems.Contains(file))
{
SelectedItems.Add(fileItem);
}
}
}
我需要一种方法来获取未选择的项目,因为 SelectionChanged 属性在取消选择时不起作用。
您不应该在视图模型中处理 UI 事件数据。
Interaction
行为通常会导致代码异味,违反 MVVM 设计规则。它只是一个多余的帮手。SelectionChanged
事件并使用事件数据获取选定和未选定的项目。从这里你有多个好的解决方案:
ICommand
实现并将数据作为命令参数传递以下示例使用附加属性来允许注册将在
ICommand
上调用的 Selector.SelectionChanged
:
SelectionData.cs
数据参数用于与视图模型交换数据。
class SelectionData<TItem>
{
public SelectionData(IEnumerable<TItem> unselectedItems, IEnumerable<TItem> selectedItems)
{
this.UnselectedItems = unselectedItems;
this.SelectedItems = selectedItems;
}
public IEnumerable<TItem> SelectedItems { get; }
public IEnumerable<TItem> UnselectedItems { get; }
}
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
public DelegateCommand<SelectionData<FileItem>> ProcessSelectedItemsCommand { get; }
= new DelegateCommand<SelectionData<FileItem>>(ExecuteProcessSelectedItemsCommand));
private void ExecuteProcessSelectedItemsCommand(SelectionData<FileItem> selectionData)
{
RemoveUnselectedFileItems(selectionData.UnselectedItems);
AddSelectedFileItems(selectionData.SelectedItems);
}
private void ExecuteProcessSelectedItemsCommand(IEnumerable<FileItem> itemsToAdd)
{
var newItemsExcludingExistingItems = selectionData.SelectedItems
.Except(this.SelectedItems);
foreach (FileItem newFileItem in newItemsExcludingExistingItems)
{
this.SelectedItems.Add(newFileItem);
}
}
private void RemoveUnselectedFileItems(IEnumerable<FileItem> itemsToRemove)
{
foreach (FileItem oldFileItem in itemsToRemove)
{
this.SelectedItems.Remove(oldFileItem);
}
}
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public static void SetFileItemsChangedCommande(UIElement attachingElement, ICommand value)
=> attachingElement.SetValue(FileItemsChangedCommandProperty, value);
public static ICommand GetFileItemsChangedCommande(UIElement attachingElement)
=> return (ICommand)attachingElement.GetValue(FileItemsChangedCommandProperty);
public static readonly DependencyProperty FileItemsChangedCommandProperty = DependencyProperty.RegisterAttached(
"FileItemsChangedCommand",
typeof(ICommand),
typeof(MainWindow),
new PropertyMetadata(default));
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
private void OnFileItemsSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var sourceElement = (UIElement)sender;
ICommand command = GetFileItemsChangedCommand(sourceElement);
IEnumerable<FileItem> oldFileItems = e.RemovedItems.Cast<FileItem>();
IEnumerable<FileItem> newFileItems = e.AddedItems.Cast<FileItem>();
var commandArgument = new SelectionData<FileItem>(oldFileItems, newFileItems);
if (command.CanExecute(commandArgument))
{
command. Execute(commandArgument);
}
}
}
MainWindow.xaml
<Window>
<ListBox MainWindow.FileItemsChangedCommand="{Binding ProcessSelectedItemsCommand}"
SelectionChanged="OnFileItemsSelectionChanged" />
</Window>