Я пытаюсь реализовать представление списка с множественным выбором в UWP, оставаясь как можно ближе к модели MVVM. Моя проблема в том, что я не могу получить выбранные элементы в модели представления через привязку.
Глядя на другие ответы на SO, я обнаружил, что единственный возможный способ добиться этого — привязать через поля Command и CommandParameter моего ListView. Ответы, однако, обычно либо были сосредоточены на простом подходе с выделенным кодом, либо были сделаны с помощью WPF, что приводило к тому, что я застревал в реализации команды.
Короткое примечание перед моим MWE: программа принимает файл .pdf в качестве входных данных и отображает его, конвертируя каждую страницу в BitmapImage. Я хочу выбрать эти отдельные страницы (BitmapImages) и выполнить действие над всеми выбранными элементами (в данном случае разные действия; мой MWE, однако, включает только одну кнопку).
Я пытаюсь реализовать представление списка с множественным выбором в UWP, оставаясь как можно ближе к модели MVVM. Моя проблема в том, что я не могу получить выбранные элементы в модели представления через привязку.
Это мой MWE:
Модель
public class PdfPageModel
{
public string Title { get; set; }
public PdfDocument PdfDoc { get; set; }
public PdfPageModel(string Title, PdfDocument pdfdoc)
{
this.Title = Title;
this.PdfDoc = pdfdoc;
}
Вид
<ListView
x:Name = "PdfPageViewer"
CanReorderItems = "True" AllowDrop = "True" CanDragItems = "True"
ItemsSource = "{x:Bind ViewModel.PdfPages}"
IsItemClickEnabled = "True"
SelectionMode = "Multiple"
IsMultiSelectCheckBoxEnabled = "False"
ScrollViewer.HorizontalScrollBarVisibility = "Auto"
ScrollViewer.HorizontalScrollMode = "Enabled"
ScrollViewer.IsHorizontalRailEnabled = "True"
ScrollViewer.ZoomMode = "Enabled"
IsZoomedInView = "False"
>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source = "{Binding }"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation = "Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<Button
CommandParameter = "{Binding SelectedItems, Mode=OneWay, ElementName=PdfPageViewer}"
Command = "{x:Bind ViewModel.SelectedPagesCommand}"
/>
ViewModel
public ObservableCollection<BitmapImage> PdfPages { get; set; }
private ICommand _selectedPagesCommand;
public ICommand SelectedPagesCommand
{
get
{
if (_selectedPagesCommand == null)
{
_selectedPagesCommand = new RelayCommand<?>(async () =>
{
// ??
});
}
return _selectedPagesCommand;
}
}
@JeroenvanLangen, к сожалению, я получаю ошибку CS0246: The type or namespace name 'SelectedListViewItemCollection' could not be found. Согласно документам кажется, что этот тип связан с Windows Forms





Наконец-то я узнал, как этого добиться. Для тех, кто любопытен или также наткнулся на эту проблему, вот что я сделал.
Я нашел эту ветку, которая в значительной степени решила то, что я пытался сделать.
ОП реализовал преобразователь (см. ниже), чтобы получить все выбранные элементы из списка в виде элемента ListView. Из документов я узнал, что возвращаемый тип свойства SelectedItems — это List интерфейс IList<>, который я реализовал в своем SelectedPagesCommand.
Затем они использовали этот преобразователь в командном вызове. (Обратите внимание, что вызов SelectedItems был удален, так как он больше не нужен из-за использования конвертера. Это необходимый и важный шаг.) Благодаря этому я наконец смог получить выбранные элементы в списке. Возвращаемые элементы были типа System.__ComObject, а не того, что ожидалось. Однако это легко обойти; просто приведите тип к тому, каким он должен быть (в моем случае это был простой BitmapImage).
Конвертер
public class ListViewSelectedItemsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var listView = value as ListView;
return listView.SelectedItems;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Вид
<Page.Resources>
<helper:ListViewSelectedItemsConverter x:Key = "ListViewSelectedItemsConverter"/>
</Page.Resources>
<!-- ... -->
<ListView
x:Name = "PdfPageViewer"
CanReorderItems = "True" AllowDrop = "True" CanDragItems = "True"
ItemsSource = "{x:Bind ViewModel.PdfPages}"
IsItemClickEnabled = "True"
SelectionMode = "Multiple"
IsMultiSelectCheckBoxEnabled = "False"
ScrollViewer.HorizontalScrollBarVisibility = "Auto"
ScrollViewer.HorizontalScrollMode = "Enabled"
ScrollViewer.IsHorizontalRailEnabled = "True"
ScrollViewer.ZoomMode = "Enabled"
IsZoomedInView = "False"
>
<ListView.ItemTemplate>
<DataTemplate>
<Image Source = "{Binding }"/>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Orientation = "Horizontal">
</StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<Button
CommandParameter = "{Binding ElementName=PdfPageViewer, Converter = {StaticResource ListViewSelectedItemsConverter}}"
Command = "{x:Bind ViewModel.SelectedPagesCommand}"
/>
ViewModel
public ObservableCollection<BitmapImage> PdfPages { get; set; }
private ObservableCollection<BitmapImage> _selectedPdfPages;
public ObservableCollection<BitmapImage> SelectedPdfPages { get; set; }
private ICommand _selectedPagesCommand;
public ICommand SelectedPagesCommand
{
get
{
if (_selectedPagesCommand == null)
{
_selectedPagesCommand = new RelayCommand<IList<object>>(async param =>
{
foreach (var i in param)
{
var img = i as BitmapImage;
SelectedPdfPages.Add(img);
}
}
}
}
}
Я думаю, что это должно быть что-то вроде:
RelayCommand<SelectedListViewItemCollection>(async arg => { // do something with arg });, потому чтоSelectedItemsимеет тип:SelectedListViewItemCollection