I'm making a simple ListView
with WinUI
and Microsoft.Toolkit.Mvvm
based on
MainPage.xaml
<Page
x:Class="ListViewWinUISample.Views.MainPage"
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:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d">
<Grid x:Name="ContentArea" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Fruits list :" Style="{StaticResource PageTitleStyle}" />
<ListView Grid.Row="1" x:Name="LvwFruits" ItemsSource="{x:Bind ViewModel.ListFruits}" BorderBrush="#212121" SelectionMode="Multiple">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{x:Bind ViewModel.GetSelectedFruits}" CommandParameter="{Binding SelectedItems, ElementName=LvwFruits}"/>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</ListView>
<TextBlock Grid.Row="2" Text="Selected fruits :" Style="{StaticResource PageTitleStyle}" />
<ListView Grid.Row="3" x:Name="LvwSelectedFruits" ItemsSource="{x:Bind ViewModel.ListSelectedFruits}" BorderBrush="#212121"/>
<StackPanel Grid.Row="4" Orientation="Horizontal">
<TextBlock Text="Count selected fruits : " VerticalAlignment="Center"/>
<TextBox Text="{Binding SelectedItems.Count, ElementName=LvwFruits}" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
</Page>
MainViewModel.cs
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ListViewWinUISample.ViewModels;
public class MainViewModel : ObservableRecipient
{
public List<string> ListFruits;
public List<string> ListSelectedFruits;
public RelayCommand<IList> GetSelectedFruits { get; set; }
public MainViewModel()
{
GetSelectedFruits = new RelayCommand<IList>(GetSelectedFruitsMethod);
var fruits = new List<string>
{
"Apple",
"Banana",
"Strawberry"
};
ListFruits = fruits;
}
private void GetSelectedFruitsMethod(IList selectedFruits)
{
Debug.WriteLine("Command successfully executed");
var listSelectedFruits = new List<string>();
foreach (var item in selectedFruits)
{
listSelectedFruits.Add(item.ToString());
Debug.WriteLine("selected fruit : " item.ToString());
}
}
}
The GetSelectedFruitsMethod
is successfully started but the parameter IList selectedFruits
in GetSelectedFruitsMethod
is always null
and I can't figure out how to get the SelectedItems
parameter from the View even if I passed it as CommandParameter
in XAML.
Thanks and regards.
CodePudding user response:
You can create a custom control like this:
ListViewEx.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Collections;
using System.Collections.Generic;
namespace ListViews;
public class ListViewEx : ListView
{
public ListViewEx() : base()
{
this.SelectionChanged = ListViewEx_SelectionChanged;
}
public new IList SelectedItems
{
get => (IList)GetValue(SelectedItemsProperty);
set => SetValue(SelectedItemsProperty, value);
}
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
nameof(SelectedItems),
typeof(IList),
typeof(ListViewEx),
new PropertyMetadata(new List<object>()));
private void ListViewEx_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (object item in e.RemovedItems)
{
SelectedItems.Remove(item);
}
foreach (object item in e.AddedItems)
{
SelectedItems.Add(item);
}
}
}
And use it like this:
MainPage.xaml
<Grid RowDefinitions="Auto,*,*">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<NumberBox
x:Name="LoadingItemsCount"
Value="1000" />
<Button
Command="{x:Bind ViewModel.LoadItemsCommand}"
CommandParameter="{x:Bind LoadingItemsCount.Value, Mode=OneWay}" />
</StackPanel>
<local:ListViewEx
Grid.Row="1"
ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}"
SelectedItems="{x:Bind ViewModel.SelectedItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionMode="Multiple">
<local:ListViewEx.Header>
<TextBlock>
<Run Text="Items: " />
<Run Text="{x:Bind ViewModel.Items.Count, Mode=OneWay}" />
</TextBlock>
</local:ListViewEx.Header>
</local:ListViewEx>
<ListView
Grid.Row="2"
ItemsSource="{x:Bind ViewModel.SelectedItems, Mode=OneWay}">
<ListView.Header>
<TextBlock>
<Run Text="Selected items: " />
<Run Text="{x:Bind ViewModel.SelectedItems.Count, Mode=OneWay}" />
</TextBlock>
</ListView.Header>
</ListView>
</Grid>
MainPage.xaml.cs
[ObservableObject]
public partial class MainPageViewModel
{
[ObservableProperty]
private ObservableCollection<string> items = new();
[ObservableProperty]
private ObservableCollection<string> selectedItems = new();
public MainPageViewModel()
{
var ilist = items as IList;
}
[RelayCommand]
private void LoadItems(double itemsCount)
{
for (int i = 0; i < itemsCount; i )
{
Items.Add(i.ToString());
}
}
}
CodePudding user response:
I finally got the answer by myself with the full MVVM way.
To retrieve SelectedItems
from first ListView
, there was just to set CommandParameter="{x:Bind LvwFruits.SelectedItems}"
and not {Binding SelectedItems, ElementName=LvwFruits}
and to replace IList
by IList<object>
.
MainPage.xaml
<Page
x:Class="ListViewWinUISample.Views.MainPage"
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:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d">
<Grid x:Name="ContentArea" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Fruits list :" Style="{StaticResource PageTitleStyle}" />
<ListView Grid.Row="1" x:Name="LvwFruits" ItemsSource="{x:Bind ViewModel.ListFruits}" BorderBrush="#212121" SelectionMode="Multiple" BorderThickness="1">
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{x:Bind ViewModel.GetSelectedFruits, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CommandParameter="{x:Bind LvwFruits.SelectedItems}"/>
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</ListView>
<TextBlock Grid.Row="2" Text="Selected fruits :" Style="{StaticResource PageTitleStyle}" />
<ListView Grid.Row="3" x:Name="LvwSelectedFruits" ItemsSource="{x:Bind ViewModel.ListSelectedFruits, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" CanDragItems="True" CanReorderItems="True" AllowDrop="True" SelectionMode="Single" BorderBrush="#212121" BorderThickness="1"/>
<StackPanel Grid.Row="4" Orientation="Horizontal">
<TextBlock Text="Count selected fruits : " VerticalAlignment="Center"/>
<TextBox Text="{x:Bind ViewModel.CountSelectedCommands, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="5,0,0,0" Width="10"/>
</StackPanel>
</Grid>
</Page>
MainViewModel.cs
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace ListViewWinUISample.ViewModels;
public class MainViewModel : ObservableRecipient
{
public List<string> ListFruits;
private ObservableCollection<string> listSelectedFruits;
public ObservableCollection<string> ListSelectedFruits
{
get => listSelectedFruits;
set => SetProperty(ref listSelectedFruits, value);
}
private int countSelectedCommands;
public int CountSelectedCommands
{
get => countSelectedCommands;
set => SetProperty(ref countSelectedCommands, value);
}
public RelayCommand<IList<object>> GetSelectedFruits
{
get; set;
}
public MainViewModel()
{
GetSelectedFruits = new RelayCommand<IList<object>>(GetSelectedFruitsMethod);
var fruits = new List<string>
{
"Apple",
"Banana",
"Strawberry"
};
ListFruits = fruits;
}
private void GetSelectedFruitsMethod(IList<object> selectedFruits)
{
if (selectedFruits != null)
{
var selected = new ObservableCollection<string>();
foreach (var item in selectedFruits)
{
selected.Add(item.ToString());
Debug.WriteLine("Selected fruit : " item.ToString());
}
ListSelectedFruits = selected;
CountSelectedCommands = selected.Count;
}
else
{
Debug.WriteLine(@"/!\ NO SELECTED FRUITS /!\");
}
}
}