WinUI 3 从 ListView 显示选定的项目

huangapple go评论131阅读模式
英文:

WinUI 3 Show selected items from ListView

问题

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.

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.

英文:

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&lt;KeyValuePair&lt;string, string&gt;&gt; ValidationFlagsList =&gt; EnumExtensions.GetAllValuesAndDescriptions&lt;ValidationFlag&gt;();

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

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

1.

&lt;ListView ItemsSource=&quot;{Binding SelectedItems, ElementName=FlagsListView, Mode=OneWay}&quot;/&gt;

2.

&lt;StackPanel DataContext=&quot;{Binding SelectedItems, ElementName=FlagsListView}&quot;&gt;
    &lt;TextBlock Text=&quot;{Binding}&quot;/&gt;
&lt;/StackPanel&gt;

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

得分: 1

ListView具有SelectedItems属性,但它只是一个普通属性,而不是DependencyProperty。不幸的是,你无法在绑定中使用它。

你可以创建一个自定义的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);
            }
        }
    }
}

并像这样使用它:

<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>
英文:

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 =&gt; (IList)GetValue(SelectedItemsProperty);
        set =&gt; SetValue(SelectedItemsProperty, value);
    }

    public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register(
        nameof(SelectedItems),
        typeof(IList),
        typeof(ListViewEx),
        new PropertyMetadata(new ObservableCollection&lt;object&gt;()));

    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:


&lt;Grid ColumnDefinitions=&quot;*,*&quot;&gt;
    &lt;local:ListViewEx
        x:Name=&quot;FlagsListView&quot;
        Grid.Column=&quot;0&quot;
        DisplayMemberPath=&quot;Value&quot;
        ItemsSource=&quot;{x:Bind ViewModel.ValidationFlagsList, Mode=OneTime}&quot;
        SelectedValuePath=&quot;Key&quot;
        SelectionMode=&quot;Multiple&quot; /&gt;

    &lt;ListView
        Grid.Column=&quot;1&quot;
        ItemsSource=&quot;{x:Bind FlagsListView.SelectedItems, Mode=OneWay}&quot; /&gt;
&lt;/Grid&gt;

huangapple
  • 本文由 发表于 2023年5月11日 16:59:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/76225848.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定