WinUI 3 Show selected items from ListView

625 Views Asked by At

I have a WinUI 3 project scaffolded using Template Studio. I have a list view populated with an Enum. I want to show my selected items in another list, but the binding does not work.
Populated with Enum meaning I take <key, value> pairs with enum value and enum description and use as ItemsSource. Selection Mode Multiple active.

public IEnumerable<KeyValuePair<string, string>> ValidationFlagsList => EnumExtensions.GetAllValuesAndDescriptions<ValidationFlag>();

//...
public static IEnumerable<KeyValuePair<string, string>> GetAllValuesAndDescriptions<TEnum>() where TEnum : struct, IConvertible, IComparable, IFormattable
{
    return typeof(TEnum).IsEnum ? (from e in Enum.GetValues(typeof(TEnum)).Cast<Enum>() select new KeyValuePair<string, string>(e.ToString(), e.GetDescription())) : throw new ArgumentException("TEnum must be an Enumeration type");
}
<ListView
        x:Name="FlagsListView"
        SelectionMode="Multiple"
        ItemsSource="{x:Bind ViewModel.ValidationFlagsList, Mode=OneTime}"
        SelectedValuePath="Key"
        DisplayMemberPath="Value">
</ListView>

In another part of xaml I want to show the selected items. I tried two variants:

1.

<ListView ItemsSource="{Binding SelectedItems, ElementName=FlagsListView, Mode=OneWay}"/>

2.

<StackPanel DataContext="{Binding SelectedItems, ElementName=FlagsListView}">
    <TextBlock Text="{Binding}"/>
</StackPanel>

Nothing shows on UI. How can I bind correctly?

Is it because IEnumerable is static and ObservableCollection is needed? But the xaml ListView should give me some straightforward binding. Documentation points to this Data binding. I read about creating a class with IsSelected property, but I only need a readonly list, preferably to add something only in xaml.

1

There are 1 best solutions below

2
Andrew KeepCoding On BEST ANSWER

The ListView does have a SelectedItems property but it's just a plain property and not a DependencyProperty. Unfortunately you can't use it with bindings.

What you can do is create a custom ListView:

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 ObservableCollection<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:


<Grid ColumnDefinitions="*,*">
    <local:ListViewEx
        x:Name="FlagsListView"
        Grid.Column="0"
        DisplayMemberPath="Value"
        ItemsSource="{x:Bind ViewModel.ValidationFlagsList, Mode=OneTime}"
        SelectedValuePath="Key"
        SelectionMode="Multiple" />

    <ListView
        Grid.Column="1"
        ItemsSource="{x:Bind FlagsListView.SelectedItems, Mode=OneWay}" />
</Grid>