I use a listview in single mode and I would like to change its visual aspect when I control-click on a row to show that this row is selected. I can't use SelectionMode="Multiple" because it doesn't match the expected result (when I normally click on a row, an action is triggered and when I select several rows via ctrl - click, a button appears to perform an action on all selected rows).
I have set some attributes on my listview like
IsItemClickEnabled="True" ItemClick="Results_ItemClick"
In Results_ItemClick, I check if the control key is pressed and I would like it to stay highlighted if I move my mouse to another line. I tried with VisualStateManager but I have the impression that moving the mouse cancels the behavior.
VisualStateManager.GoToState(sender as Control, "Selected", true);
I thought of adding the item to the SelectedItems of the listview but SelectedItems doesn't allow the addition.
Is there a way to do this?
Thank you.
CodePudding user response:
You can do it this way:
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
namespace ListViewTests;
public class Item
{
public int Id { get; set; }
public string Text { get; set; } = string.Empty;
}
public partial class MainPageViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Item> items = new();
public MainPageViewModel()
{
for (int i = 0; i < 10000; i )
{
Items.Add(new Item { Id = Items.Count 1, Text = $"Item {i 1}" });
}
}
}
MainPage.xaml
<Page
x:Class="ListViewTests.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:local="using:ListViewTests"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid RowDefinitions="Auto,*">
<StackPanel
Grid.Row="0"
Orientation="Horizontal">
<TextBlock Text="Operations" />
<Button
x:Name="ProcessSelectedItemsButton"
Click="ProcessSelectedItemsButton_Click"
Content="Process selected items"
Visibility="Collapsed" />
</StackPanel>
<ListView
x:Name="ListViewControl"
Grid.Row="1"
IsItemClickEnabled="True"
ItemsSource="{x:Bind ViewModel.Items, Mode=OneWay}"
SelectionChanged="ListViewControl_SelectionChanged"
SelectionMode="Extended">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<Grid ColumnDefinitions="30,*,Auto">
<TextBlock
Grid.Column="0"
Text="{x:Bind Id, Mode=OneWay}" />
<TextBlock
Grid.Column="1"
Text="{x:Bind Text, Mode=OneWay}" />
<Button
Grid.Column="2"
Click="ListItemButton_Click"
Content="Ctrl Click to select multiple items" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
MainPage.xaml.cs
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using System.Diagnostics;
using System.Linq;
using Windows.System;
using Windows.UI.Core;
namespace ListViewTests;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public MainPageViewModel ViewModel { get; } = new();
public static bool IsControlKeyDown()
{
return InputKeyboardSource
.GetKeyStateForCurrentThread(VirtualKey.Control)
.HasFlag(CoreVirtualKeyStates.Down);
}
private void ProcessSelectedItemsButton_Click(object sender, RoutedEventArgs _)
{
foreach (Item item in this.ListViewControl.SelectedItems.OfType<Item>())
{
// Do your logic here...
Debug.WriteLine($"Processed Item Id: {item.Id} Text: {item.Text}.");
}
}
private void ListItemButton_Click(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
if (IsControlKeyDown() is false)
{
ItemIndexRange allItemsRange = new(
firstIndex: 0,
length: (uint)this.ListViewControl.Items.Count);
this.ListViewControl.DeselectRange(allItemsRange);
}
int itemIndex = this.ListViewControl.Items.IndexOf(button.DataContext);
ItemIndexRange selectedItemRange = new(
firstIndex: itemIndex,
length: 1);
this.ListViewControl.SelectRange(selectedItemRange);
}
}
private void ListViewControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.ProcessSelectedItemsButton.Visibility = (sender as ListView)?.SelectedItems.Count > 1
? Visibility.Visible
: Visibility.Collapsed;
}
}