Home > OS >  WinUI 3 Highlight listview item on ctrl - click
WinUI 3 Highlight listview item on ctrl - click

Time:02-03

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;
    }
}
  • Related